From 7e8a70154d29ab60c5d06889c17c048b87f1e419 Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Sun, 1 Sep 2024 12:32:10 -0400 Subject: [PATCH 01/15] feat: --use-network flag for top-level network enablement of all catalogers Signed-off-by: Keith Zantow --- cmd/syft/internal/options/catalog.go | 20 +++++++++++++++++--- cmd/syft/internal/options/golang.go | 4 ++-- cmd/syft/internal/options/java.go | 4 ++-- cmd/syft/internal/options/javascript.go | 2 +- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/cmd/syft/internal/options/catalog.go b/cmd/syft/internal/options/catalog.go index 99359abec51..0413ef823f3 100644 --- a/cmd/syft/internal/options/catalog.go +++ b/cmd/syft/internal/options/catalog.go @@ -36,6 +36,7 @@ type Catalog struct { Scope string `yaml:"scope" json:"scope" mapstructure:"scope"` Parallelism int `yaml:"parallelism" json:"parallelism" mapstructure:"parallelism"` // the number of catalog workers to run in parallel Relationships relationshipsConfig `yaml:"relationships" json:"relationships" mapstructure:"relationships"` + UseNetwork *bool `yaml:"use-network" json:"use-network" mapstructure:"use-network"` // ecosystem-specific cataloger configuration Golang golangConfig `yaml:"golang" json:"golang" mapstructure:"golang"` @@ -132,7 +133,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { Golang: golang.DefaultCatalogerConfig(). WithSearchLocalModCacheLicenses(cfg.Golang.SearchLocalModCacheLicenses). WithLocalModCacheDir(cfg.Golang.LocalModCacheDir). - WithSearchRemoteLicenses(cfg.Golang.SearchRemoteLicenses). + WithSearchRemoteLicenses(multilevelOption(cfg.UseNetwork, cfg.Golang.SearchRemoteLicenses)). WithProxy(cfg.Golang.Proxy). WithNoProxy(cfg.Golang.NoProxy). WithMainModuleVersion( @@ -142,7 +143,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { WithFromLDFlags(cfg.Golang.MainModuleVersion.FromLDFlags), ), JavaScript: javascript.DefaultCatalogerConfig(). - WithSearchRemoteLicenses(cfg.JavaScript.SearchRemoteLicenses). + WithSearchRemoteLicenses(multilevelOption(cfg.UseNetwork, cfg.JavaScript.SearchRemoteLicenses)). WithNpmBaseURL(cfg.JavaScript.NpmBaseURL), LinuxKernel: kernel.LinuxKernelCatalogerConfig{ CatalogModules: cfg.LinuxKernel.CatalogModules, @@ -153,7 +154,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { JavaArchive: java.DefaultArchiveCatalogerConfig(). WithUseMavenLocalRepository(cfg.Java.UseMavenLocalRepository). WithMavenLocalRepositoryDir(cfg.Java.MavenLocalRepositoryDir). - WithUseNetwork(cfg.Java.UseNetwork). + WithUseNetwork(multilevelOption(cfg.UseNetwork, cfg.Java.UseNetwork)). WithMavenBaseURL(cfg.Java.MavenURL). WithArchiveTraversal(archiveSearch, cfg.Java.MaxParentRecursiveDepth), } @@ -201,6 +202,9 @@ func (cfg *Catalog) AddFlags(flags clio.FlagSet) { flags.StringVarP(&cfg.Source.BasePath, "base-path", "", "base directory for scanning, no links will be followed above this directory, and all paths will be reported relative to this directory") + + flags.BoolPtrVarP(&cfg.UseNetwork, "use-network", "", + "use the network to resolve locally unavailable data") } func (cfg *Catalog) DescribeFields(descriptions fangs.FieldDescriptionSet) { @@ -243,3 +247,13 @@ func (cfg *Catalog) PostLoad() error { return nil } + +func multilevelOption(options ...*bool) bool { + def := false + for _, option := range options { + if option != nil { + def = *option + } + } + return def +} diff --git a/cmd/syft/internal/options/golang.go b/cmd/syft/internal/options/golang.go index 63ac1bcc7c8..d8073275928 100644 --- a/cmd/syft/internal/options/golang.go +++ b/cmd/syft/internal/options/golang.go @@ -10,7 +10,7 @@ import ( type golangConfig struct { SearchLocalModCacheLicenses bool `json:"search-local-mod-cache-licenses" yaml:"search-local-mod-cache-licenses" mapstructure:"search-local-mod-cache-licenses"` LocalModCacheDir string `json:"local-mod-cache-dir" yaml:"local-mod-cache-dir" mapstructure:"local-mod-cache-dir"` - SearchRemoteLicenses bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"` + SearchRemoteLicenses *bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"` Proxy string `json:"proxy" yaml:"proxy" mapstructure:"proxy"` NoProxy string `json:"no-proxy" yaml:"no-proxy" mapstructure:"no-proxy"` MainModuleVersion golangMainModuleVersionConfig `json:"main-module-version" yaml:"main-module-version" mapstructure:"main-module-version"` @@ -49,7 +49,7 @@ func defaultGolangConfig() golangConfig { return golangConfig{ SearchLocalModCacheLicenses: def.SearchLocalModCacheLicenses, LocalModCacheDir: def.LocalModCacheDir, - SearchRemoteLicenses: def.SearchRemoteLicenses, + SearchRemoteLicenses: nil, // this defaults to false, which is the API default Proxy: strings.Join(def.Proxies, ","), NoProxy: strings.Join(def.NoProxy, ","), MainModuleVersion: golangMainModuleVersionConfig{ diff --git a/cmd/syft/internal/options/java.go b/cmd/syft/internal/options/java.go index 8894c760b75..ab381a3917e 100644 --- a/cmd/syft/internal/options/java.go +++ b/cmd/syft/internal/options/java.go @@ -6,7 +6,7 @@ import ( ) type javaConfig struct { - UseNetwork bool `yaml:"use-network" json:"use-network" mapstructure:"use-network"` + UseNetwork *bool `yaml:"use-network" json:"use-network" mapstructure:"use-network"` UseMavenLocalRepository bool `yaml:"use-maven-local-repository" json:"use-maven-local-repository" mapstructure:"use-maven-local-repository"` MavenLocalRepositoryDir string `yaml:"maven-local-repository-dir" json:"maven-local-repository-dir" mapstructure:"maven-local-repository-dir"` MavenURL string `yaml:"maven-url" json:"maven-url" mapstructure:"maven-url"` @@ -17,7 +17,7 @@ func defaultJavaConfig() javaConfig { def := java.DefaultArchiveCatalogerConfig() return javaConfig{ - UseNetwork: def.UseNetwork, + UseNetwork: nil, // this defaults to "false", which is the API default MaxParentRecursiveDepth: def.MaxParentRecursiveDepth, UseMavenLocalRepository: def.UseMavenLocalRepository, MavenLocalRepositoryDir: def.MavenLocalRepositoryDir, diff --git a/cmd/syft/internal/options/javascript.go b/cmd/syft/internal/options/javascript.go index 5f88c0f33f4..e618037ccaa 100644 --- a/cmd/syft/internal/options/javascript.go +++ b/cmd/syft/internal/options/javascript.go @@ -3,7 +3,7 @@ package options import "github.com/anchore/clio" type javaScriptConfig struct { - SearchRemoteLicenses bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"` + SearchRemoteLicenses *bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"` NpmBaseURL string `json:"npm-base-url" yaml:"npm-base-url" mapstructure:"npm-base-url"` } From f6c8376ac296b406af61cd878cece4ca579789e1 Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Tue, 3 Sep 2024 14:11:24 -0400 Subject: [PATCH 02/15] chore: PR feedback, update fangs Signed-off-by: Keith Zantow --- cmd/syft/internal/options/catalog.go | 16 ++------- go.mod | 24 ++++++------- go.sum | 52 ++++++++++++++-------------- 3 files changed, 41 insertions(+), 51 deletions(-) diff --git a/cmd/syft/internal/options/catalog.go b/cmd/syft/internal/options/catalog.go index 0413ef823f3..1a29b055ebf 100644 --- a/cmd/syft/internal/options/catalog.go +++ b/cmd/syft/internal/options/catalog.go @@ -133,7 +133,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { Golang: golang.DefaultCatalogerConfig(). WithSearchLocalModCacheLicenses(cfg.Golang.SearchLocalModCacheLicenses). WithLocalModCacheDir(cfg.Golang.LocalModCacheDir). - WithSearchRemoteLicenses(multilevelOption(cfg.UseNetwork, cfg.Golang.SearchRemoteLicenses)). + WithSearchRemoteLicenses(*multiLevelOption(false, cfg.UseNetwork, cfg.Golang.SearchRemoteLicenses)). WithProxy(cfg.Golang.Proxy). WithNoProxy(cfg.Golang.NoProxy). WithMainModuleVersion( @@ -143,7 +143,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { WithFromLDFlags(cfg.Golang.MainModuleVersion.FromLDFlags), ), JavaScript: javascript.DefaultCatalogerConfig(). - WithSearchRemoteLicenses(multilevelOption(cfg.UseNetwork, cfg.JavaScript.SearchRemoteLicenses)). + WithSearchRemoteLicenses(*multiLevelOption(false, cfg.UseNetwork, cfg.JavaScript.SearchRemoteLicenses)). WithNpmBaseURL(cfg.JavaScript.NpmBaseURL), LinuxKernel: kernel.LinuxKernelCatalogerConfig{ CatalogModules: cfg.LinuxKernel.CatalogModules, @@ -154,7 +154,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { JavaArchive: java.DefaultArchiveCatalogerConfig(). WithUseMavenLocalRepository(cfg.Java.UseMavenLocalRepository). WithMavenLocalRepositoryDir(cfg.Java.MavenLocalRepositoryDir). - WithUseNetwork(multilevelOption(cfg.UseNetwork, cfg.Java.UseNetwork)). + WithUseNetwork(*multiLevelOption(false, cfg.UseNetwork, cfg.Java.UseNetwork)). WithMavenBaseURL(cfg.Java.MavenURL). WithArchiveTraversal(archiveSearch, cfg.Java.MaxParentRecursiveDepth), } @@ -247,13 +247,3 @@ func (cfg *Catalog) PostLoad() error { return nil } - -func multilevelOption(options ...*bool) bool { - def := false - for _, option := range options { - if option != nil { - def = *option - } - } - return def -} diff --git a/go.mod b/go.mod index 8e6a7ea63dd..5941ae690e7 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/acobaugh/osrelease v0.1.0 github.com/anchore/bubbly v0.0.0-20231115134915-def0aba654a9 github.com/anchore/clio v0.0.0-20240522144804-d81e109008aa - github.com/anchore/fangs v0.0.0-20240508143433-f016b099950f + github.com/anchore/fangs v0.0.0-20240903175602-e716ef12c23d github.com/anchore/go-collections v0.0.0-20240216171411-9321230ce537 github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb @@ -84,7 +84,7 @@ require ( modernc.org/sqlite v1.32.0 ) -require google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect +require google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect require ( github.com/BurntSushi/toml v1.4.0 @@ -136,13 +136,13 @@ require ( github.com/emirpasic/gods v1.18.1 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/felixge/fgprof v0.9.3 // indirect - github.com/felixge/httpsnoop v1.0.3 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.4 // indirect github.com/gkampitakis/ciinfo v0.3.0 // indirect github.com/gkampitakis/go-diff v1.3.2 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-restruct/restruct v1.2.0-alpha // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -186,7 +186,7 @@ require ( github.com/opencontainers/runtime-spec v1.1.0-rc.1 // indirect github.com/opencontainers/selinux v1.11.0 // indirect github.com/pborman/indent v1.2.1 // indirect - github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pierrec/lz4/v4 v4.1.19 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -205,7 +205,7 @@ require ( github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/cast v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.18.2 // indirect + github.com/spf13/viper v1.19.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/sylabs/sif/v2 v2.17.1 // indirect github.com/sylabs/squashfs v1.0.0 // indirect @@ -222,10 +222,10 @@ require ( github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect - go.opentelemetry.io/otel v1.19.0 // indirect - go.opentelemetry.io/otel/metric v1.19.0 // indirect - go.opentelemetry.io/otel/trace v1.19.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/crypto v0.26.0 // indirect @@ -235,8 +235,8 @@ require ( golang.org/x/text v0.17.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect - google.golang.org/grpc v1.59.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect + google.golang.org/grpc v1.62.1 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect diff --git a/go.sum b/go.sum index 0cc5381b240..1ae49ca012d 100644 --- a/go.sum +++ b/go.sum @@ -97,8 +97,8 @@ github.com/anchore/bubbly v0.0.0-20231115134915-def0aba654a9 h1:p0ZIe0htYOX284Y4 github.com/anchore/bubbly v0.0.0-20231115134915-def0aba654a9/go.mod h1:3ZsFB9tzW3vl4gEiUeuSOMDnwroWxIxJelOOHUp8dSw= github.com/anchore/clio v0.0.0-20240522144804-d81e109008aa h1:pwlAn4O9SBUnlgfa69YcqIynbUyobLVFYu8HxSoCffA= github.com/anchore/clio v0.0.0-20240522144804-d81e109008aa/go.mod h1:nD3H5uIvjxlfmakOBgtyFQbk5Zjp3l538kxfpHPslzI= -github.com/anchore/fangs v0.0.0-20240508143433-f016b099950f h1:NOhzafCyNYFi88qxkBFjMzQo4dRa1vDhBzx+0Uovx8Q= -github.com/anchore/fangs v0.0.0-20240508143433-f016b099950f/go.mod h1:sVpRS2yNCw6tLVpvA1QSDVWTJVpCuAm8JNZgn4Sjz/k= +github.com/anchore/fangs v0.0.0-20240903175602-e716ef12c23d h1:ZD4wdCBgJJzJybjTUIEiiupLF7B9H3WLuBTjspBO2Mc= +github.com/anchore/fangs v0.0.0-20240903175602-e716ef12c23d/go.mod h1:Xh4ObY3fmoMzOEVXwDtS1uK44JC7+nRD0n29/1KYFYg= github.com/anchore/go-collections v0.0.0-20240216171411-9321230ce537 h1:GjNGuwK5jWjJMyVppBjYS54eOiiSNv4Ba869k4wh72Q= github.com/anchore/go-collections v0.0.0-20240216171411-9321230ce537/go.mod h1:1aiktV46ATCkuVg0O573ZrH56BUawTECPETbZyBcqT8= github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a h1:nJ2G8zWKASyVClGVgG7sfM5mwoZlZ2zYpIzN2OhjWkw= @@ -277,8 +277,8 @@ github.com/fatih/set v0.2.1 h1:nn2CaJyknWE/6txyUDGwysr3G5QC6xWB/PtVjPBbeaA= github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI= github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= -github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= @@ -315,8 +315,8 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-restruct/restruct v1.2.0-alpha h1:2Lp474S/9660+SJjpVxoKuWX09JsXHSrdV7Nv3/gkvc= @@ -624,8 +624,8 @@ github.com/pborman/indent v1.2.1/go.mod h1:FitS+t35kIYtB5xWTZAPhnmrxcciEEOdbyrrp github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.19 h1:tYLzDnjDXh9qIxSTKHwXwOYmm9d887Y7Y1ZkyXYHAN4= github.com/pierrec/lz4/v4 v4.1.19/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= @@ -733,8 +733,8 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= -github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= -github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -826,20 +826,20 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= -go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= -go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= @@ -1263,12 +1263,12 @@ google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= -google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= -google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo= -google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= +google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 h1:rIo7ocm2roD9DcFIX67Ym8icoGCKSARAiPljFhh5suQ= +google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c h1:lfpJ/2rWPa/kJgxyyXM8PrNnfCzcmxJ265mADgwmvLI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1296,8 +1296,8 @@ google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 437ea7d02279903ee0e5350a10facbc9d0fb1a19 Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Tue, 3 Sep 2024 14:46:46 -0400 Subject: [PATCH 03/15] chore: wording Signed-off-by: Keith Zantow --- cmd/syft/internal/options/catalog.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/syft/internal/options/catalog.go b/cmd/syft/internal/options/catalog.go index 1a29b055ebf..1460136d1bf 100644 --- a/cmd/syft/internal/options/catalog.go +++ b/cmd/syft/internal/options/catalog.go @@ -204,7 +204,7 @@ func (cfg *Catalog) AddFlags(flags clio.FlagSet) { "base directory for scanning, no links will be followed above this directory, and all paths will be reported relative to this directory") flags.BoolPtrVarP(&cfg.UseNetwork, "use-network", "", - "use the network to resolve locally unavailable data") + "use the network to fetch and augment package information") } func (cfg *Catalog) DescribeFields(descriptions fangs.FieldDescriptionSet) { From aa35bc9f771d84fa77c01d5b78fafafc4f1cd4ec Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Wed, 4 Sep 2024 17:01:53 -0400 Subject: [PATCH 04/15] feat: implement network selector similar to cataloger selector Signed-off-by: Keith Zantow --- cmd/syft/internal/commands/attest.go | 9 ++- cmd/syft/internal/commands/convert.go | 3 +- cmd/syft/internal/commands/packages.go | 2 +- cmd/syft/internal/commands/root.go | 2 +- cmd/syft/internal/commands/scan.go | 9 ++- cmd/syft/internal/commands/update.go | 4 +- cmd/syft/internal/options/catalog.go | 30 ++----- cmd/syft/internal/options/network.go | 98 +++++++++++++++++++++++ cmd/syft/internal/options/network_test.go | 58 ++++++++++++++ cmd/syft/internal/options/update_check.go | 10 ++- internal/task/executor.go | 2 +- 11 files changed, 185 insertions(+), 42 deletions(-) create mode 100644 cmd/syft/internal/options/network.go create mode 100644 cmd/syft/internal/options/network_test.go diff --git a/cmd/syft/internal/commands/attest.go b/cmd/syft/internal/commands/attest.go index fa3b5ceef52..60bd8f0b590 100644 --- a/cmd/syft/internal/commands/attest.go +++ b/cmd/syft/internal/commands/attest.go @@ -40,6 +40,7 @@ const ( type attestOptions struct { options.Config `yaml:",inline" mapstructure:",squash"` options.Output `yaml:",inline" mapstructure:",squash"` + options.Network `yaml:",inline" mapstructure:",squash"` options.UpdateCheck `yaml:",inline" mapstructure:",squash"` options.Catalog `yaml:",inline" mapstructure:",squash"` Attest options.Attest `yaml:"attest" mapstructure:"attest"` @@ -63,7 +64,7 @@ func Attest(app clio.Application) *cobra.Command { "command": "attest", }), Args: validateScanArgs, - PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck), + PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Network), RunE: func(cmd *cobra.Command, args []string) error { restoreStdout := ui.CaptureStdoutToTraceLog() defer restoreStdout() @@ -113,7 +114,7 @@ func runAttest(ctx context.Context, id clio.Identification, opts *attestOptions, } defer os.Remove(f.Name()) - s, err := generateSBOMForAttestation(ctx, id, &opts.Catalog, userInput) + s, err := generateSBOMForAttestation(ctx, id, &opts.Catalog, opts.Network, userInput) if err != nil { return fmt.Errorf("unable to build SBOM: %w", err) } @@ -247,7 +248,7 @@ func predicateType(outputName string) string { } } -func generateSBOMForAttestation(ctx context.Context, id clio.Identification, opts *options.Catalog, userInput string) (*sbom.SBOM, error) { +func generateSBOMForAttestation(ctx context.Context, id clio.Identification, opts *options.Catalog, net options.Network, userInput string) (*sbom.SBOM, error) { if len(opts.From) > 1 || (len(opts.From) == 1 && opts.From[0] != stereoscope.RegistryTag) { return nil, fmt.Errorf("attest requires use of an OCI registry directly, one or more of the specified sources is unsupported: %v", opts.From) } @@ -266,7 +267,7 @@ func generateSBOMForAttestation(ctx context.Context, id clio.Identification, opt } }() - s, err := generateSBOM(ctx, id, src, opts) + s, err := generateSBOM(ctx, id, src, opts, net) if err != nil { return nil, err } diff --git a/cmd/syft/internal/commands/convert.go b/cmd/syft/internal/commands/convert.go index 510027ce7f5..bd6a81741ce 100644 --- a/cmd/syft/internal/commands/convert.go +++ b/cmd/syft/internal/commands/convert.go @@ -25,6 +25,7 @@ const ( type ConvertOptions struct { options.Config `yaml:",inline" mapstructure:",squash"` options.Output `yaml:",inline" mapstructure:",squash"` + options.Network `yaml:",inline" mapstructure:",squash"` options.UpdateCheck `yaml:",inline" mapstructure:",squash"` } @@ -45,7 +46,7 @@ func Convert(app clio.Application) *cobra.Command { "command": "convert", }), Args: validateConvertArgs, - PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck), + PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Network), RunE: func(_ *cobra.Command, args []string) error { restoreStdout := ui.CaptureStdoutToTraceLog() defer restoreStdout() diff --git a/cmd/syft/internal/commands/packages.go b/cmd/syft/internal/commands/packages.go index 92f225d1d57..3b35148c2c8 100644 --- a/cmd/syft/internal/commands/packages.go +++ b/cmd/syft/internal/commands/packages.go @@ -22,7 +22,7 @@ func Packages(app clio.Application, scanCmd *cobra.Command) *cobra.Command { "appName": id.Name, "command": "packages", }), - PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck), + PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Network), RunE: func(cmd *cobra.Command, args []string) error { restoreStdout := ui.CaptureStdoutToTraceLog() defer restoreStdout() diff --git a/cmd/syft/internal/commands/root.go b/cmd/syft/internal/commands/root.go index bfc508bf33e..9fa660e9c87 100644 --- a/cmd/syft/internal/commands/root.go +++ b/cmd/syft/internal/commands/root.go @@ -20,7 +20,7 @@ func Root(app clio.Application, packagesCmd *cobra.Command) *cobra.Command { Long: packagesCmd.Long, Args: packagesCmd.Args, Example: packagesCmd.Example, - PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck), + PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Network), RunE: func(cmd *cobra.Command, args []string) error { restoreStdout := ui.CaptureStdoutToTraceLog() defer restoreStdout() diff --git a/cmd/syft/internal/commands/scan.go b/cmd/syft/internal/commands/scan.go index 48fcc8c1ebc..2e145eee88f 100644 --- a/cmd/syft/internal/commands/scan.go +++ b/cmd/syft/internal/commands/scan.go @@ -66,6 +66,7 @@ const ( type scanOptions struct { options.Config `yaml:",inline" mapstructure:",squash"` options.Output `yaml:",inline" mapstructure:",squash"` + options.Network `yaml:",inline" mapstructure:",squash"` options.UpdateCheck `yaml:",inline" mapstructure:",squash"` options.Catalog `yaml:",inline" mapstructure:",squash"` Cache options.Cache `json:"-" yaml:"cache" mapstructure:"cache"` @@ -94,7 +95,7 @@ func Scan(app clio.Application) *cobra.Command { "command": "scan", }), Args: validateScanArgs, - PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck), + PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Network), RunE: func(cmd *cobra.Command, args []string) error { restoreStdout := ui.CaptureStdoutToTraceLog() defer restoreStdout() @@ -196,7 +197,7 @@ func runScan(ctx context.Context, id clio.Identification, opts *scanOptions, use } }() - s, err := generateSBOM(ctx, id, src, &opts.Catalog) + s, err := generateSBOM(ctx, id, src, &opts.Catalog, opts.Network) if err != nil { return err } @@ -253,8 +254,8 @@ func getSource(ctx context.Context, opts *options.Catalog, userInput string, sou return src, nil } -func generateSBOM(ctx context.Context, id clio.Identification, src source.Source, opts *options.Catalog) (*sbom.SBOM, error) { - s, err := syft.CreateSBOM(ctx, src, opts.ToSBOMConfig(id)) +func generateSBOM(ctx context.Context, id clio.Identification, src source.Source, opts *options.Catalog, net options.Network) (*sbom.SBOM, error) { + s, err := syft.CreateSBOM(ctx, src, opts.ToSBOMConfig(id, net)) if err != nil { expErrs := filterExpressionErrors(err) notifyExpressionErrors(expErrs) diff --git a/cmd/syft/internal/commands/update.go b/cmd/syft/internal/commands/update.go index 27629ff499d..820c31aeafa 100644 --- a/cmd/syft/internal/commands/update.go +++ b/cmd/syft/internal/commands/update.go @@ -27,9 +27,9 @@ var latestAppVersionURL = struct { path: "/syft/releases/latest/VERSION", } -func applicationUpdateCheck(id clio.Identification, check *options.UpdateCheck) func(cmd *cobra.Command, args []string) error { +func applicationUpdateCheck(id clio.Identification, check *options.UpdateCheck, net *options.Network) func(cmd *cobra.Command, args []string) error { return func(_ *cobra.Command, _ []string) error { - if check.CheckForAppUpdate { + if check.DoCheckForAppUpdate(*net) { checkForApplicationUpdate(id) } return nil diff --git a/cmd/syft/internal/options/catalog.go b/cmd/syft/internal/options/catalog.go index 1460136d1bf..79047481144 100644 --- a/cmd/syft/internal/options/catalog.go +++ b/cmd/syft/internal/options/catalog.go @@ -2,8 +2,6 @@ package options import ( "fmt" - "sort" - "strings" "github.com/iancoleman/strcase" @@ -36,7 +34,6 @@ type Catalog struct { Scope string `yaml:"scope" json:"scope" mapstructure:"scope"` Parallelism int `yaml:"parallelism" json:"parallelism" mapstructure:"parallelism"` // the number of catalog workers to run in parallel Relationships relationshipsConfig `yaml:"relationships" json:"relationships" mapstructure:"relationships"` - UseNetwork *bool `yaml:"use-network" json:"use-network" mapstructure:"use-network"` // ecosystem-specific cataloger configuration Golang golangConfig `yaml:"golang" json:"golang" mapstructure:"golang"` @@ -73,13 +70,13 @@ func DefaultCatalog() Catalog { } } -func (cfg Catalog) ToSBOMConfig(id clio.Identification) *syft.CreateSBOMConfig { +func (cfg Catalog) ToSBOMConfig(id clio.Identification, net Network) *syft.CreateSBOMConfig { return syft.DefaultCreateSBOMConfig(). WithTool(id.Name, id.Version). WithParallelism(cfg.Parallelism). WithRelationshipsConfig(cfg.ToRelationshipsConfig()). WithSearchConfig(cfg.ToSearchConfig()). - WithPackagesConfig(cfg.ToPackagesConfig()). + WithPackagesConfig(cfg.ToPackagesConfig(net)). WithFilesConfig(cfg.ToFilesConfig()). WithCatalogerSelection( pkgcataloging.NewSelectionRequest(). @@ -123,7 +120,7 @@ func (cfg Catalog) ToFilesConfig() filecataloging.Config { } } -func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { +func (cfg Catalog) ToPackagesConfig(net Network) pkgcataloging.Config { archiveSearch := cataloging.ArchiveSearchConfig{ IncludeIndexedArchives: cfg.Package.SearchIndexedArchives, IncludeUnindexedArchives: cfg.Package.SearchUnindexedArchives, @@ -133,7 +130,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { Golang: golang.DefaultCatalogerConfig(). WithSearchLocalModCacheLicenses(cfg.Golang.SearchLocalModCacheLicenses). WithLocalModCacheDir(cfg.Golang.LocalModCacheDir). - WithSearchRemoteLicenses(*multiLevelOption(false, cfg.UseNetwork, cfg.Golang.SearchRemoteLicenses)). + WithSearchRemoteLicenses(*multiLevelOption(false, net.Enabled("golang", "go"), cfg.Golang.SearchRemoteLicenses)). WithProxy(cfg.Golang.Proxy). WithNoProxy(cfg.Golang.NoProxy). WithMainModuleVersion( @@ -143,7 +140,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { WithFromLDFlags(cfg.Golang.MainModuleVersion.FromLDFlags), ), JavaScript: javascript.DefaultCatalogerConfig(). - WithSearchRemoteLicenses(*multiLevelOption(false, cfg.UseNetwork, cfg.JavaScript.SearchRemoteLicenses)). + WithSearchRemoteLicenses(*multiLevelOption(false, net.Enabled("javascript", "js"), cfg.JavaScript.SearchRemoteLicenses)). WithNpmBaseURL(cfg.JavaScript.NpmBaseURL), LinuxKernel: kernel.LinuxKernelCatalogerConfig{ CatalogModules: cfg.LinuxKernel.CatalogModules, @@ -154,7 +151,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { JavaArchive: java.DefaultArchiveCatalogerConfig(). WithUseMavenLocalRepository(cfg.Java.UseMavenLocalRepository). WithMavenLocalRepositoryDir(cfg.Java.MavenLocalRepositoryDir). - WithUseNetwork(*multiLevelOption(false, cfg.UseNetwork, cfg.Java.UseNetwork)). + WithUseNetwork(*multiLevelOption(false, net.Enabled("java", "maven"), cfg.Java.UseNetwork)). WithMavenBaseURL(cfg.Java.MavenURL). WithArchiveTraversal(archiveSearch, cfg.Java.MaxParentRecursiveDepth), } @@ -202,9 +199,6 @@ func (cfg *Catalog) AddFlags(flags clio.FlagSet) { flags.StringVarP(&cfg.Source.BasePath, "base-path", "", "base directory for scanning, no links will be followed above this directory, and all paths will be reported relative to this directory") - - flags.BoolPtrVarP(&cfg.UseNetwork, "use-network", "", - "use the network to fetch and augment package information") } func (cfg *Catalog) DescribeFields(descriptions fangs.FieldDescriptionSet) { @@ -219,18 +213,6 @@ func (cfg *Catalog) PostLoad() error { return fmt.Errorf("cannot use both 'catalogers' and 'select-catalogers'/'default-catalogers' flags") } - flatten := func(l []string) []string { - var out []string - for _, v := range l { - for _, s := range strings.Split(v, ",") { - out = append(out, strings.TrimSpace(s)) - } - } - sort.Strings(out) - - return out - } - cfg.From = flatten(cfg.From) cfg.Catalogers = flatten(cfg.Catalogers) diff --git a/cmd/syft/internal/options/network.go b/cmd/syft/internal/options/network.go new file mode 100644 index 00000000000..556109ec95a --- /dev/null +++ b/cmd/syft/internal/options/network.go @@ -0,0 +1,98 @@ +package options + +import ( + "sort" + "strings" + + "github.com/anchore/clio" + "github.com/anchore/fangs" + "github.com/anchore/syft/internal/log" +) + +type Network struct { + Directives []string `yaml:"network" json:"network" mapstructure:"network"` +} + +func (n *Network) PostLoad() error { + n.Directives = flatten(n.Directives) + return nil +} + +func (n *Network) AddFlags(flags clio.FlagSet) { + flags.StringArrayVarP(&n.Directives, "network", "", + "use the network to fetch and augment package information") + + // if pfp, ok := flags.(fangs.PFlagSetProvider); ok { + // flagSet := pfp.PFlagSet() + // flag := flagSet.Lookup("network") + // flag.NoOptDefVal = "all" + //} +} + +func (n *Network) Enabled(features ...string) *bool { + return networkEnabled(n.Directives, features...) +} + +var _ interface { + fangs.PostLoader + fangs.FlagAdder +} = (*Network)(nil) + +func networkEnabled(networkDirectives []string, features ...string) *bool { + if len(networkDirectives) == 0 { + return nil + } + + enabled := func(features ...string) *bool { + for _, directive := range networkDirectives { + enable := true + directive = strings.TrimPrefix(directive, "+") // +java and java are equivalent + if strings.HasPrefix(directive, "-") { + directive = directive[1:] + enable = false + } + for _, feature := range features { + if directive == feature { + return &enable + } + } + } + return nil + } + + enableAll := enabled("all", "yes", "on", "enable", "enabled") + disableAll := enabled("none", "no", "off", "disable", "disabled") + + if disableAll != nil { + if enableAll != nil { + log.Warn("you have specified to both enable and disable all network functionality, defaulting to disabled") + } else { + enableAll = ptr(!*disableAll) + } + } + + // check for explicit enable/disable of each particular feature, in order + for _, feat := range features { + enableFeature := enabled(feat) + if enableFeature != nil { + return enableFeature + } + } + + return enableAll +} + +func ptr[T any](val T) *T { + return &val +} + +func flatten(commaSeparatedEntries []string) []string { + var out []string + for _, v := range commaSeparatedEntries { + for _, s := range strings.Split(v, ",") { + out = append(out, strings.TrimSpace(s)) + } + } + sort.Strings(out) + return out +} diff --git a/cmd/syft/internal/options/network_test.go b/cmd/syft/internal/options/network_test.go new file mode 100644 index 00000000000..70845b2704d --- /dev/null +++ b/cmd/syft/internal/options/network_test.go @@ -0,0 +1,58 @@ +package options + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_networkEnabled(t *testing.T) { + tests := []struct { + directives string + test string + expected *bool + }{ + { + directives: "", + test: "java", + expected: nil, + }, + { + directives: "none", + test: "java", + expected: ptr(false), + }, + { + directives: "none,+java", + test: "java", + expected: ptr(true), + }, + { + directives: "all", + test: "java", + expected: ptr(true), + }, + { + directives: "on", + test: "java", + expected: ptr(true), + }, + { + directives: "on,-java", + test: "java", + expected: ptr(false), + }, + } + + for _, test := range tests { + t.Run(test.directives, func(t *testing.T) { + n := Network{ + Directives: []string{test.directives}, + } + require.NoError(t, n.PostLoad()) + + got := n.Enabled(test.test) + require.Equal(t, test.expected, got) + }) + } +} diff --git a/cmd/syft/internal/options/update_check.go b/cmd/syft/internal/options/update_check.go index 0f396a5d9fc..b9a0af9f3b9 100644 --- a/cmd/syft/internal/options/update_check.go +++ b/cmd/syft/internal/options/update_check.go @@ -3,13 +3,15 @@ package options import "github.com/anchore/fangs" type UpdateCheck struct { - CheckForAppUpdate bool `yaml:"check-for-app-update" json:"check-for-app-update" mapstructure:"check-for-app-update"` // whether to check for an application update on start up or not + CheckForAppUpdate *bool `yaml:"check-for-app-update" json:"check-for-app-update" mapstructure:"check-for-app-update"` // whether to check for an application update on start up or not } func DefaultUpdateCheck() UpdateCheck { - return UpdateCheck{ - CheckForAppUpdate: true, - } + return UpdateCheck{} +} + +func (cfg *UpdateCheck) DoCheckForAppUpdate(net Network) bool { + return *multiLevelOption(true, net.Enabled("update-check"), cfg.CheckForAppUpdate) } func (cfg *UpdateCheck) DescribeFields(descriptions fangs.FieldDescriptionSet) { diff --git a/internal/task/executor.go b/internal/task/executor.go index 2935f61b12c..899796424be 100644 --- a/internal/task/executor.go +++ b/internal/task/executor.go @@ -7,9 +7,9 @@ import ( "sync" "time" - "github.com/anchore/syft/internal/log" "github.com/hashicorp/go-multierror" + "github.com/anchore/syft/internal/log" "github.com/anchore/syft/internal/sbomsync" "github.com/anchore/syft/syft/event/monitor" "github.com/anchore/syft/syft/file" From 7629dc18f53428bdfa90d4425aa707990f7e877a Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Wed, 4 Sep 2024 17:27:28 -0400 Subject: [PATCH 05/15] chore: update tests Signed-off-by: Keith Zantow --- cmd/syft/internal/commands/attest_test.go | 2 +- cmd/syft/internal/test/integration/files_test.go | 4 ++-- cmd/syft/internal/test/integration/utils_test.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/syft/internal/commands/attest_test.go b/cmd/syft/internal/commands/attest_test.go index 41a26822664..a5ef0fbead7 100644 --- a/cmd/syft/internal/commands/attest_test.go +++ b/cmd/syft/internal/commands/attest_test.go @@ -264,7 +264,7 @@ func Test_buildSBOMForAttestation(t *testing.T) { if tt.wantErr == nil { tt.wantErr = require.NoError } - _, err := generateSBOMForAttestation(context.Background(), tt.args.id, tt.args.opts, tt.args.userInput) + _, err := generateSBOMForAttestation(context.Background(), tt.args.id, tt.args.opts, options.Network{}, tt.args.userInput) tt.wantErr(t, err) if err != nil { return diff --git a/cmd/syft/internal/test/integration/files_test.go b/cmd/syft/internal/test/integration/files_test.go index 6794eed08eb..07bfb9540fc 100644 --- a/cmd/syft/internal/test/integration/files_test.go +++ b/cmd/syft/internal/test/integration/files_test.go @@ -20,7 +20,7 @@ import ( ) func TestFileCataloging_Default(t *testing.T) { - cfg := options.DefaultCatalog().ToSBOMConfig(clio.Identification{}) + cfg := options.DefaultCatalog().ToSBOMConfig(clio.Identification{}, options.Network{}) cfg = cfg.WithFilesConfig(filecataloging.DefaultConfig()) sbom, _ := catalogDirectoryWithConfig(t, "test-fixtures/files", cfg) @@ -34,7 +34,7 @@ func TestFileCataloging_Default(t *testing.T) { } func TestFileCataloging_AllFiles(t *testing.T) { - cfg := options.DefaultCatalog().ToSBOMConfig(clio.Identification{}) + cfg := options.DefaultCatalog().ToSBOMConfig(clio.Identification{}, options.Network{}) cfg = cfg.WithFilesConfig(filecataloging.Config{ Selection: file.AllFilesSelection, Hashers: []crypto.Hash{ diff --git a/cmd/syft/internal/test/integration/utils_test.go b/cmd/syft/internal/test/integration/utils_test.go index 4e1ffb2096f..d7cdb2dbef1 100644 --- a/cmd/syft/internal/test/integration/utils_test.go +++ b/cmd/syft/internal/test/integration/utils_test.go @@ -19,7 +19,7 @@ func catalogFixtureImage(t *testing.T, fixtureImageName string, scope source.Sco cfg := options.DefaultCatalog().ToSBOMConfig(clio.Identification{ Name: "syft-tester", Version: "v0.99.0", - }).WithCatalogerSelection( + }, options.Network{}).WithCatalogerSelection( pkgcataloging.NewSelectionRequest(). WithExpression(catalogerSelection...), ) @@ -54,7 +54,7 @@ func catalogDirectory(t *testing.T, dir string, catalogerSelection ...string) (s cfg := options.DefaultCatalog().ToSBOMConfig(clio.Identification{ Name: "syft-tester", Version: "v0.99.0", - }).WithCatalogerSelection( + }, options.Network{}).WithCatalogerSelection( pkgcataloging.NewSelectionRequest(). WithExpression(catalogerSelection...), ) From af8160bac25df18a86b2c87c83c70b8a757ea53c Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Wed, 4 Sep 2024 20:14:49 -0400 Subject: [PATCH 06/15] chore: simplify change Signed-off-by: Keith Zantow --- cmd/syft/internal/commands/attest.go | 9 +++--- cmd/syft/internal/commands/attest_test.go | 2 +- cmd/syft/internal/commands/convert.go | 2 +- cmd/syft/internal/commands/packages.go | 2 +- cmd/syft/internal/commands/root.go | 2 +- cmd/syft/internal/commands/scan.go | 9 +++--- cmd/syft/internal/options/catalog.go | 26 +++++++++++++---- cmd/syft/internal/options/network.go | 28 ++++--------------- cmd/syft/internal/options/network_test.go | 2 +- .../internal/test/integration/files_test.go | 4 +-- .../internal/test/integration/utils_test.go | 4 +-- 11 files changed, 42 insertions(+), 48 deletions(-) diff --git a/cmd/syft/internal/commands/attest.go b/cmd/syft/internal/commands/attest.go index 60bd8f0b590..fe0bb6c720e 100644 --- a/cmd/syft/internal/commands/attest.go +++ b/cmd/syft/internal/commands/attest.go @@ -40,7 +40,6 @@ const ( type attestOptions struct { options.Config `yaml:",inline" mapstructure:",squash"` options.Output `yaml:",inline" mapstructure:",squash"` - options.Network `yaml:",inline" mapstructure:",squash"` options.UpdateCheck `yaml:",inline" mapstructure:",squash"` options.Catalog `yaml:",inline" mapstructure:",squash"` Attest options.Attest `yaml:"attest" mapstructure:"attest"` @@ -64,7 +63,7 @@ func Attest(app clio.Application) *cobra.Command { "command": "attest", }), Args: validateScanArgs, - PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Network), + PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Catalog.Network), RunE: func(cmd *cobra.Command, args []string) error { restoreStdout := ui.CaptureStdoutToTraceLog() defer restoreStdout() @@ -114,7 +113,7 @@ func runAttest(ctx context.Context, id clio.Identification, opts *attestOptions, } defer os.Remove(f.Name()) - s, err := generateSBOMForAttestation(ctx, id, &opts.Catalog, opts.Network, userInput) + s, err := generateSBOMForAttestation(ctx, id, &opts.Catalog, userInput) if err != nil { return fmt.Errorf("unable to build SBOM: %w", err) } @@ -248,7 +247,7 @@ func predicateType(outputName string) string { } } -func generateSBOMForAttestation(ctx context.Context, id clio.Identification, opts *options.Catalog, net options.Network, userInput string) (*sbom.SBOM, error) { +func generateSBOMForAttestation(ctx context.Context, id clio.Identification, opts *options.Catalog, userInput string) (*sbom.SBOM, error) { if len(opts.From) > 1 || (len(opts.From) == 1 && opts.From[0] != stereoscope.RegistryTag) { return nil, fmt.Errorf("attest requires use of an OCI registry directly, one or more of the specified sources is unsupported: %v", opts.From) } @@ -267,7 +266,7 @@ func generateSBOMForAttestation(ctx context.Context, id clio.Identification, opt } }() - s, err := generateSBOM(ctx, id, src, opts, net) + s, err := generateSBOM(ctx, id, src, opts) if err != nil { return nil, err } diff --git a/cmd/syft/internal/commands/attest_test.go b/cmd/syft/internal/commands/attest_test.go index a5ef0fbead7..41a26822664 100644 --- a/cmd/syft/internal/commands/attest_test.go +++ b/cmd/syft/internal/commands/attest_test.go @@ -264,7 +264,7 @@ func Test_buildSBOMForAttestation(t *testing.T) { if tt.wantErr == nil { tt.wantErr = require.NoError } - _, err := generateSBOMForAttestation(context.Background(), tt.args.id, tt.args.opts, options.Network{}, tt.args.userInput) + _, err := generateSBOMForAttestation(context.Background(), tt.args.id, tt.args.opts, tt.args.userInput) tt.wantErr(t, err) if err != nil { return diff --git a/cmd/syft/internal/commands/convert.go b/cmd/syft/internal/commands/convert.go index bd6a81741ce..07d9db7b6cc 100644 --- a/cmd/syft/internal/commands/convert.go +++ b/cmd/syft/internal/commands/convert.go @@ -25,7 +25,7 @@ const ( type ConvertOptions struct { options.Config `yaml:",inline" mapstructure:",squash"` options.Output `yaml:",inline" mapstructure:",squash"` - options.Network `yaml:",inline" mapstructure:",squash"` + options.Network `yaml:"network" mapstructure:"network"` options.UpdateCheck `yaml:",inline" mapstructure:",squash"` } diff --git a/cmd/syft/internal/commands/packages.go b/cmd/syft/internal/commands/packages.go index 3b35148c2c8..fe7410aadf7 100644 --- a/cmd/syft/internal/commands/packages.go +++ b/cmd/syft/internal/commands/packages.go @@ -22,7 +22,7 @@ func Packages(app clio.Application, scanCmd *cobra.Command) *cobra.Command { "appName": id.Name, "command": "packages", }), - PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Network), + PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Catalog.Network), RunE: func(cmd *cobra.Command, args []string) error { restoreStdout := ui.CaptureStdoutToTraceLog() defer restoreStdout() diff --git a/cmd/syft/internal/commands/root.go b/cmd/syft/internal/commands/root.go index 9fa660e9c87..88b3d82a0a4 100644 --- a/cmd/syft/internal/commands/root.go +++ b/cmd/syft/internal/commands/root.go @@ -20,7 +20,7 @@ func Root(app clio.Application, packagesCmd *cobra.Command) *cobra.Command { Long: packagesCmd.Long, Args: packagesCmd.Args, Example: packagesCmd.Example, - PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Network), + PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Catalog.Network), RunE: func(cmd *cobra.Command, args []string) error { restoreStdout := ui.CaptureStdoutToTraceLog() defer restoreStdout() diff --git a/cmd/syft/internal/commands/scan.go b/cmd/syft/internal/commands/scan.go index 2e145eee88f..6473b931fd9 100644 --- a/cmd/syft/internal/commands/scan.go +++ b/cmd/syft/internal/commands/scan.go @@ -66,7 +66,6 @@ const ( type scanOptions struct { options.Config `yaml:",inline" mapstructure:",squash"` options.Output `yaml:",inline" mapstructure:",squash"` - options.Network `yaml:",inline" mapstructure:",squash"` options.UpdateCheck `yaml:",inline" mapstructure:",squash"` options.Catalog `yaml:",inline" mapstructure:",squash"` Cache options.Cache `json:"-" yaml:"cache" mapstructure:"cache"` @@ -95,7 +94,7 @@ func Scan(app clio.Application) *cobra.Command { "command": "scan", }), Args: validateScanArgs, - PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Network), + PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Catalog.Network), RunE: func(cmd *cobra.Command, args []string) error { restoreStdout := ui.CaptureStdoutToTraceLog() defer restoreStdout() @@ -197,7 +196,7 @@ func runScan(ctx context.Context, id clio.Identification, opts *scanOptions, use } }() - s, err := generateSBOM(ctx, id, src, &opts.Catalog, opts.Network) + s, err := generateSBOM(ctx, id, src, &opts.Catalog) if err != nil { return err } @@ -254,8 +253,8 @@ func getSource(ctx context.Context, opts *options.Catalog, userInput string, sou return src, nil } -func generateSBOM(ctx context.Context, id clio.Identification, src source.Source, opts *options.Catalog, net options.Network) (*sbom.SBOM, error) { - s, err := syft.CreateSBOM(ctx, src, opts.ToSBOMConfig(id, net)) +func generateSBOM(ctx context.Context, id clio.Identification, src source.Source, opts *options.Catalog) (*sbom.SBOM, error) { + s, err := syft.CreateSBOM(ctx, src, opts.ToSBOMConfig(id)) if err != nil { expErrs := filterExpressionErrors(err) notifyExpressionErrors(expErrs) diff --git a/cmd/syft/internal/options/catalog.go b/cmd/syft/internal/options/catalog.go index 79047481144..5589dabd438 100644 --- a/cmd/syft/internal/options/catalog.go +++ b/cmd/syft/internal/options/catalog.go @@ -2,6 +2,8 @@ package options import ( "fmt" + "sort" + "strings" "github.com/iancoleman/strcase" @@ -34,6 +36,7 @@ type Catalog struct { Scope string `yaml:"scope" json:"scope" mapstructure:"scope"` Parallelism int `yaml:"parallelism" json:"parallelism" mapstructure:"parallelism"` // the number of catalog workers to run in parallel Relationships relationshipsConfig `yaml:"relationships" json:"relationships" mapstructure:"relationships"` + Network Network `yaml:"network" json:"network" mapstructure:"network"` // ecosystem-specific cataloger configuration Golang golangConfig `yaml:"golang" json:"golang" mapstructure:"golang"` @@ -70,13 +73,13 @@ func DefaultCatalog() Catalog { } } -func (cfg Catalog) ToSBOMConfig(id clio.Identification, net Network) *syft.CreateSBOMConfig { +func (cfg Catalog) ToSBOMConfig(id clio.Identification) *syft.CreateSBOMConfig { return syft.DefaultCreateSBOMConfig(). WithTool(id.Name, id.Version). WithParallelism(cfg.Parallelism). WithRelationshipsConfig(cfg.ToRelationshipsConfig()). WithSearchConfig(cfg.ToSearchConfig()). - WithPackagesConfig(cfg.ToPackagesConfig(net)). + WithPackagesConfig(cfg.ToPackagesConfig()). WithFilesConfig(cfg.ToFilesConfig()). WithCatalogerSelection( pkgcataloging.NewSelectionRequest(). @@ -120,7 +123,7 @@ func (cfg Catalog) ToFilesConfig() filecataloging.Config { } } -func (cfg Catalog) ToPackagesConfig(net Network) pkgcataloging.Config { +func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { archiveSearch := cataloging.ArchiveSearchConfig{ IncludeIndexedArchives: cfg.Package.SearchIndexedArchives, IncludeUnindexedArchives: cfg.Package.SearchUnindexedArchives, @@ -130,7 +133,7 @@ func (cfg Catalog) ToPackagesConfig(net Network) pkgcataloging.Config { Golang: golang.DefaultCatalogerConfig(). WithSearchLocalModCacheLicenses(cfg.Golang.SearchLocalModCacheLicenses). WithLocalModCacheDir(cfg.Golang.LocalModCacheDir). - WithSearchRemoteLicenses(*multiLevelOption(false, net.Enabled("golang", "go"), cfg.Golang.SearchRemoteLicenses)). + WithSearchRemoteLicenses(*multiLevelOption(false, cfg.Network.Enabled("golang", "go"), cfg.Golang.SearchRemoteLicenses)). WithProxy(cfg.Golang.Proxy). WithNoProxy(cfg.Golang.NoProxy). WithMainModuleVersion( @@ -140,7 +143,7 @@ func (cfg Catalog) ToPackagesConfig(net Network) pkgcataloging.Config { WithFromLDFlags(cfg.Golang.MainModuleVersion.FromLDFlags), ), JavaScript: javascript.DefaultCatalogerConfig(). - WithSearchRemoteLicenses(*multiLevelOption(false, net.Enabled("javascript", "js"), cfg.JavaScript.SearchRemoteLicenses)). + WithSearchRemoteLicenses(*multiLevelOption(false, cfg.Network.Enabled("javascript", "js"), cfg.JavaScript.SearchRemoteLicenses)). WithNpmBaseURL(cfg.JavaScript.NpmBaseURL), LinuxKernel: kernel.LinuxKernelCatalogerConfig{ CatalogModules: cfg.LinuxKernel.CatalogModules, @@ -151,7 +154,7 @@ func (cfg Catalog) ToPackagesConfig(net Network) pkgcataloging.Config { JavaArchive: java.DefaultArchiveCatalogerConfig(). WithUseMavenLocalRepository(cfg.Java.UseMavenLocalRepository). WithMavenLocalRepositoryDir(cfg.Java.MavenLocalRepositoryDir). - WithUseNetwork(*multiLevelOption(false, net.Enabled("java", "maven"), cfg.Java.UseNetwork)). + WithUseNetwork(*multiLevelOption(false, cfg.Network.Enabled("java", "maven"), cfg.Java.UseNetwork)). WithMavenBaseURL(cfg.Java.MavenURL). WithArchiveTraversal(archiveSearch, cfg.Java.MaxParentRecursiveDepth), } @@ -229,3 +232,14 @@ func (cfg *Catalog) PostLoad() error { return nil } + +func flatten(commaSeparatedEntries []string) []string { + var out []string + for _, v := range commaSeparatedEntries { + for _, s := range strings.Split(v, ",") { + out = append(out, strings.TrimSpace(s)) + } + } + sort.Strings(out) + return out +} diff --git a/cmd/syft/internal/options/network.go b/cmd/syft/internal/options/network.go index 556109ec95a..df9e5971d28 100644 --- a/cmd/syft/internal/options/network.go +++ b/cmd/syft/internal/options/network.go @@ -1,7 +1,6 @@ package options import ( - "sort" "strings" "github.com/anchore/clio" @@ -10,27 +9,21 @@ import ( ) type Network struct { - Directives []string `yaml:"network" json:"network" mapstructure:"network"` + Enable []string `yaml:"enable" json:"enable" mapstructure:"enable"` } func (n *Network) PostLoad() error { - n.Directives = flatten(n.Directives) + n.Enable = flatten(n.Enable) return nil } func (n *Network) AddFlags(flags clio.FlagSet) { - flags.StringArrayVarP(&n.Directives, "network", "", - "use the network to fetch and augment package information") - - // if pfp, ok := flags.(fangs.PFlagSetProvider); ok { - // flagSet := pfp.PFlagSet() - // flag := flagSet.Lookup("network") - // flag.NoOptDefVal = "all" - //} + flags.StringArrayVarP(&n.Enable, "network", "", + "enable features to use the network to fetch and augment package information") } func (n *Network) Enabled(features ...string) *bool { - return networkEnabled(n.Directives, features...) + return networkEnabled(n.Enable, features...) } var _ interface { @@ -85,14 +78,3 @@ func networkEnabled(networkDirectives []string, features ...string) *bool { func ptr[T any](val T) *T { return &val } - -func flatten(commaSeparatedEntries []string) []string { - var out []string - for _, v := range commaSeparatedEntries { - for _, s := range strings.Split(v, ",") { - out = append(out, strings.TrimSpace(s)) - } - } - sort.Strings(out) - return out -} diff --git a/cmd/syft/internal/options/network_test.go b/cmd/syft/internal/options/network_test.go index 70845b2704d..52a173c5017 100644 --- a/cmd/syft/internal/options/network_test.go +++ b/cmd/syft/internal/options/network_test.go @@ -47,7 +47,7 @@ func Test_networkEnabled(t *testing.T) { for _, test := range tests { t.Run(test.directives, func(t *testing.T) { n := Network{ - Directives: []string{test.directives}, + Enable: []string{test.directives}, } require.NoError(t, n.PostLoad()) diff --git a/cmd/syft/internal/test/integration/files_test.go b/cmd/syft/internal/test/integration/files_test.go index 07bfb9540fc..6794eed08eb 100644 --- a/cmd/syft/internal/test/integration/files_test.go +++ b/cmd/syft/internal/test/integration/files_test.go @@ -20,7 +20,7 @@ import ( ) func TestFileCataloging_Default(t *testing.T) { - cfg := options.DefaultCatalog().ToSBOMConfig(clio.Identification{}, options.Network{}) + cfg := options.DefaultCatalog().ToSBOMConfig(clio.Identification{}) cfg = cfg.WithFilesConfig(filecataloging.DefaultConfig()) sbom, _ := catalogDirectoryWithConfig(t, "test-fixtures/files", cfg) @@ -34,7 +34,7 @@ func TestFileCataloging_Default(t *testing.T) { } func TestFileCataloging_AllFiles(t *testing.T) { - cfg := options.DefaultCatalog().ToSBOMConfig(clio.Identification{}, options.Network{}) + cfg := options.DefaultCatalog().ToSBOMConfig(clio.Identification{}) cfg = cfg.WithFilesConfig(filecataloging.Config{ Selection: file.AllFilesSelection, Hashers: []crypto.Hash{ diff --git a/cmd/syft/internal/test/integration/utils_test.go b/cmd/syft/internal/test/integration/utils_test.go index d7cdb2dbef1..4e1ffb2096f 100644 --- a/cmd/syft/internal/test/integration/utils_test.go +++ b/cmd/syft/internal/test/integration/utils_test.go @@ -19,7 +19,7 @@ func catalogFixtureImage(t *testing.T, fixtureImageName string, scope source.Sco cfg := options.DefaultCatalog().ToSBOMConfig(clio.Identification{ Name: "syft-tester", Version: "v0.99.0", - }, options.Network{}).WithCatalogerSelection( + }).WithCatalogerSelection( pkgcataloging.NewSelectionRequest(). WithExpression(catalogerSelection...), ) @@ -54,7 +54,7 @@ func catalogDirectory(t *testing.T, dir string, catalogerSelection ...string) (s cfg := options.DefaultCatalog().ToSBOMConfig(clio.Identification{ Name: "syft-tester", Version: "v0.99.0", - }, options.Network{}).WithCatalogerSelection( + }).WithCatalogerSelection( pkgcataloging.NewSelectionRequest(). WithExpression(catalogerSelection...), ) From 3afdf420fab615ecdb1ec446ecb5a2892f2bc2a8 Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Wed, 4 Sep 2024 20:28:25 -0400 Subject: [PATCH 07/15] chore: consistency Signed-off-by: Keith Zantow --- cmd/syft/internal/commands/update.go | 2 +- cmd/syft/internal/options/network.go | 3 +++ cmd/syft/internal/options/update_check.go | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd/syft/internal/commands/update.go b/cmd/syft/internal/commands/update.go index 820c31aeafa..d1a22d17f60 100644 --- a/cmd/syft/internal/commands/update.go +++ b/cmd/syft/internal/commands/update.go @@ -29,7 +29,7 @@ var latestAppVersionURL = struct { func applicationUpdateCheck(id clio.Identification, check *options.UpdateCheck, net *options.Network) func(cmd *cobra.Command, args []string) error { return func(_ *cobra.Command, _ []string) error { - if check.DoCheckForAppUpdate(*net) { + if check.DoCheckForAppUpdate(net) { checkForApplicationUpdate(id) } return nil diff --git a/cmd/syft/internal/options/network.go b/cmd/syft/internal/options/network.go index df9e5971d28..5ebccc4999f 100644 --- a/cmd/syft/internal/options/network.go +++ b/cmd/syft/internal/options/network.go @@ -23,6 +23,9 @@ func (n *Network) AddFlags(flags clio.FlagSet) { } func (n *Network) Enabled(features ...string) *bool { + if n == nil { + return nil + } return networkEnabled(n.Enable, features...) } diff --git a/cmd/syft/internal/options/update_check.go b/cmd/syft/internal/options/update_check.go index b9a0af9f3b9..5abae032193 100644 --- a/cmd/syft/internal/options/update_check.go +++ b/cmd/syft/internal/options/update_check.go @@ -10,7 +10,7 @@ func DefaultUpdateCheck() UpdateCheck { return UpdateCheck{} } -func (cfg *UpdateCheck) DoCheckForAppUpdate(net Network) bool { +func (cfg *UpdateCheck) DoCheckForAppUpdate(net *Network) bool { return *multiLevelOption(true, net.Enabled("update-check"), cfg.CheckForAppUpdate) } From 25bb7b4bd09ac002ffbbf349793179e01cc41a4d Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Wed, 4 Sep 2024 20:54:57 -0400 Subject: [PATCH 08/15] chore: minor tweaks Signed-off-by: Keith Zantow --- cmd/syft/internal/options/network.go | 5 ++--- cmd/syft/internal/options/network_test.go | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/cmd/syft/internal/options/network.go b/cmd/syft/internal/options/network.go index 5ebccc4999f..a2946d23ff2 100644 --- a/cmd/syft/internal/options/network.go +++ b/cmd/syft/internal/options/network.go @@ -62,12 +62,11 @@ func networkEnabled(networkDirectives []string, features ...string) *bool { if disableAll != nil { if enableAll != nil { log.Warn("you have specified to both enable and disable all network functionality, defaulting to disabled") - } else { - enableAll = ptr(!*disableAll) } + enableAll = ptr(!*disableAll) } - // check for explicit enable/disable of each particular feature, in order + // check for explicit enable/disable of feature names for _, feat := range features { enableFeature := enabled(feat) if enableFeature != nil { diff --git a/cmd/syft/internal/options/network_test.go b/cmd/syft/internal/options/network_test.go index 52a173c5017..593f48f8251 100644 --- a/cmd/syft/internal/options/network_test.go +++ b/cmd/syft/internal/options/network_test.go @@ -27,11 +27,31 @@ func Test_networkEnabled(t *testing.T) { test: "java", expected: ptr(true), }, + { + directives: "all,none", + test: "java", + expected: ptr(false), + }, { directives: "all", test: "java", expected: ptr(true), }, + { + directives: "golang,js", + test: "java", + expected: nil, + }, + { + directives: "golang,-js,java", + test: "java", + expected: ptr(true), + }, + { + directives: "golang,js,-java", + test: "java", + expected: ptr(false), + }, { directives: "on", test: "java", From 3b01ac2d2a75d5edd8fcc5dfb11dc21b5878bbcb Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Fri, 6 Sep 2024 11:46:56 -0400 Subject: [PATCH 09/15] chore: refactor to --enrich flag Signed-off-by: Keith Zantow --- cmd/syft/internal/commands/attest.go | 2 +- cmd/syft/internal/commands/convert.go | 3 +- cmd/syft/internal/commands/packages.go | 2 +- cmd/syft/internal/commands/root.go | 2 +- cmd/syft/internal/commands/scan.go | 2 +- cmd/syft/internal/commands/update.go | 4 +- cmd/syft/internal/options/catalog.go | 62 +++++++++++++++-- cmd/syft/internal/options/catalog_test.go | 66 ++++++++++++++++++ cmd/syft/internal/options/network.go | 82 ----------------------- cmd/syft/internal/options/network_test.go | 78 --------------------- cmd/syft/internal/options/update_check.go | 10 ++- internal/task/executor.go | 2 +- 12 files changed, 136 insertions(+), 179 deletions(-) delete mode 100644 cmd/syft/internal/options/network.go delete mode 100644 cmd/syft/internal/options/network_test.go diff --git a/cmd/syft/internal/commands/attest.go b/cmd/syft/internal/commands/attest.go index fe0bb6c720e..fa3b5ceef52 100644 --- a/cmd/syft/internal/commands/attest.go +++ b/cmd/syft/internal/commands/attest.go @@ -63,7 +63,7 @@ func Attest(app clio.Application) *cobra.Command { "command": "attest", }), Args: validateScanArgs, - PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Catalog.Network), + PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck), RunE: func(cmd *cobra.Command, args []string) error { restoreStdout := ui.CaptureStdoutToTraceLog() defer restoreStdout() diff --git a/cmd/syft/internal/commands/convert.go b/cmd/syft/internal/commands/convert.go index 07d9db7b6cc..510027ce7f5 100644 --- a/cmd/syft/internal/commands/convert.go +++ b/cmd/syft/internal/commands/convert.go @@ -25,7 +25,6 @@ const ( type ConvertOptions struct { options.Config `yaml:",inline" mapstructure:",squash"` options.Output `yaml:",inline" mapstructure:",squash"` - options.Network `yaml:"network" mapstructure:"network"` options.UpdateCheck `yaml:",inline" mapstructure:",squash"` } @@ -46,7 +45,7 @@ func Convert(app clio.Application) *cobra.Command { "command": "convert", }), Args: validateConvertArgs, - PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Network), + PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck), RunE: func(_ *cobra.Command, args []string) error { restoreStdout := ui.CaptureStdoutToTraceLog() defer restoreStdout() diff --git a/cmd/syft/internal/commands/packages.go b/cmd/syft/internal/commands/packages.go index fe7410aadf7..92f225d1d57 100644 --- a/cmd/syft/internal/commands/packages.go +++ b/cmd/syft/internal/commands/packages.go @@ -22,7 +22,7 @@ func Packages(app clio.Application, scanCmd *cobra.Command) *cobra.Command { "appName": id.Name, "command": "packages", }), - PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Catalog.Network), + PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck), RunE: func(cmd *cobra.Command, args []string) error { restoreStdout := ui.CaptureStdoutToTraceLog() defer restoreStdout() diff --git a/cmd/syft/internal/commands/root.go b/cmd/syft/internal/commands/root.go index 88b3d82a0a4..bfc508bf33e 100644 --- a/cmd/syft/internal/commands/root.go +++ b/cmd/syft/internal/commands/root.go @@ -20,7 +20,7 @@ func Root(app clio.Application, packagesCmd *cobra.Command) *cobra.Command { Long: packagesCmd.Long, Args: packagesCmd.Args, Example: packagesCmd.Example, - PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Catalog.Network), + PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck), RunE: func(cmd *cobra.Command, args []string) error { restoreStdout := ui.CaptureStdoutToTraceLog() defer restoreStdout() diff --git a/cmd/syft/internal/commands/scan.go b/cmd/syft/internal/commands/scan.go index 6473b931fd9..48fcc8c1ebc 100644 --- a/cmd/syft/internal/commands/scan.go +++ b/cmd/syft/internal/commands/scan.go @@ -94,7 +94,7 @@ func Scan(app clio.Application) *cobra.Command { "command": "scan", }), Args: validateScanArgs, - PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck, &opts.Catalog.Network), + PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck), RunE: func(cmd *cobra.Command, args []string) error { restoreStdout := ui.CaptureStdoutToTraceLog() defer restoreStdout() diff --git a/cmd/syft/internal/commands/update.go b/cmd/syft/internal/commands/update.go index d1a22d17f60..27629ff499d 100644 --- a/cmd/syft/internal/commands/update.go +++ b/cmd/syft/internal/commands/update.go @@ -27,9 +27,9 @@ var latestAppVersionURL = struct { path: "/syft/releases/latest/VERSION", } -func applicationUpdateCheck(id clio.Identification, check *options.UpdateCheck, net *options.Network) func(cmd *cobra.Command, args []string) error { +func applicationUpdateCheck(id clio.Identification, check *options.UpdateCheck) func(cmd *cobra.Command, args []string) error { return func(_ *cobra.Command, _ []string) error { - if check.DoCheckForAppUpdate(net) { + if check.CheckForAppUpdate { checkForApplicationUpdate(id) } return nil diff --git a/cmd/syft/internal/options/catalog.go b/cmd/syft/internal/options/catalog.go index 5589dabd438..44ba7b2cf74 100644 --- a/cmd/syft/internal/options/catalog.go +++ b/cmd/syft/internal/options/catalog.go @@ -36,7 +36,7 @@ type Catalog struct { Scope string `yaml:"scope" json:"scope" mapstructure:"scope"` Parallelism int `yaml:"parallelism" json:"parallelism" mapstructure:"parallelism"` // the number of catalog workers to run in parallel Relationships relationshipsConfig `yaml:"relationships" json:"relationships" mapstructure:"relationships"` - Network Network `yaml:"network" json:"network" mapstructure:"network"` + Enrich []string `yaml:"enrich" json:"enrich" mapstructure:"enrich"` // ecosystem-specific cataloger configuration Golang golangConfig `yaml:"golang" json:"golang" mapstructure:"golang"` @@ -133,7 +133,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { Golang: golang.DefaultCatalogerConfig(). WithSearchLocalModCacheLicenses(cfg.Golang.SearchLocalModCacheLicenses). WithLocalModCacheDir(cfg.Golang.LocalModCacheDir). - WithSearchRemoteLicenses(*multiLevelOption(false, cfg.Network.Enabled("golang", "go"), cfg.Golang.SearchRemoteLicenses)). + WithSearchRemoteLicenses(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, "golang", "go"), cfg.Golang.SearchRemoteLicenses)). WithProxy(cfg.Golang.Proxy). WithNoProxy(cfg.Golang.NoProxy). WithMainModuleVersion( @@ -143,7 +143,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { WithFromLDFlags(cfg.Golang.MainModuleVersion.FromLDFlags), ), JavaScript: javascript.DefaultCatalogerConfig(). - WithSearchRemoteLicenses(*multiLevelOption(false, cfg.Network.Enabled("javascript", "js"), cfg.JavaScript.SearchRemoteLicenses)). + WithSearchRemoteLicenses(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, "javascript", "js"), cfg.JavaScript.SearchRemoteLicenses)). WithNpmBaseURL(cfg.JavaScript.NpmBaseURL), LinuxKernel: kernel.LinuxKernelCatalogerConfig{ CatalogModules: cfg.LinuxKernel.CatalogModules, @@ -154,7 +154,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { JavaArchive: java.DefaultArchiveCatalogerConfig(). WithUseMavenLocalRepository(cfg.Java.UseMavenLocalRepository). WithMavenLocalRepositoryDir(cfg.Java.MavenLocalRepositoryDir). - WithUseNetwork(*multiLevelOption(false, cfg.Network.Enabled("java", "maven"), cfg.Java.UseNetwork)). + WithUseNetwork(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, "java", "maven"), cfg.Java.UseNetwork)). WithMavenBaseURL(cfg.Java.MavenURL). WithArchiveTraversal(archiveSearch, cfg.Java.MaxParentRecursiveDepth), } @@ -194,6 +194,9 @@ func (cfg *Catalog) AddFlags(flags clio.FlagSet) { flags.StringArrayVarP(&cfg.SelectCatalogers, "select-catalogers", "", "add, remove, and filter the catalogers to be used") + flags.StringArrayVarP(&cfg.Enrich, "enrich", "", + "enable data enrichment operations, which can utilize services such as Maven Central and NPM") + flags.StringVarP(&cfg.Source.Name, "source-name", "", "set the name of the target being analyzed") @@ -206,6 +209,9 @@ func (cfg *Catalog) AddFlags(flags clio.FlagSet) { func (cfg *Catalog) DescribeFields(descriptions fangs.FieldDescriptionSet) { descriptions.Add(&cfg.Parallelism, "number of cataloger workers to run in parallel") + + descriptions.Add(&cfg.Enrich, `enable/disable data enrichment operations. By default all enrichment is disabled, use: all to enable everything. +Prefixing with a minus will remove the enrichment, e.g. enrich: [all, -java] would enable all except java enrichment. `) } func (cfg *Catalog) PostLoad() error { @@ -221,6 +227,7 @@ func (cfg *Catalog) PostLoad() error { cfg.Catalogers = flatten(cfg.Catalogers) cfg.DefaultCatalogers = flatten(cfg.DefaultCatalogers) cfg.SelectCatalogers = flatten(cfg.SelectCatalogers) + cfg.Enrich = flatten(cfg.Enrich) // for backwards compatibility cfg.DefaultCatalogers = append(cfg.DefaultCatalogers, cfg.Catalogers...) @@ -243,3 +250,50 @@ func flatten(commaSeparatedEntries []string) []string { sort.Strings(out) return out } + +func enrichmentEnabled(enrichDirectives []string, features ...string) *bool { + if len(enrichDirectives) == 0 { + return nil + } + + enabled := func(features ...string) *bool { + for _, directive := range enrichDirectives { + enable := true + directive = strings.TrimPrefix(directive, "+") // +java and java are equivalent + if strings.HasPrefix(directive, "-") { + directive = directive[1:] + enable = false + } + for _, feature := range features { + if directive == feature { + return &enable + } + } + } + return nil + } + + enableAll := enabled("all") + disableAll := enabled("none") + + if disableAll != nil { + if enableAll != nil { + log.Warn("you have specified to both enable and disable all network functionality, defaulting to disabled") + } + enableAll = ptr(!*disableAll) + } + + // check for explicit enable/disable of feature names + for _, feat := range features { + enableFeature := enabled(feat) + if enableFeature != nil { + return enableFeature + } + } + + return enableAll +} + +func ptr[T any](val T) *T { + return &val +} diff --git a/cmd/syft/internal/options/catalog_test.go b/cmd/syft/internal/options/catalog_test.go index f9a54249ae3..a9b730fdacb 100644 --- a/cmd/syft/internal/options/catalog_test.go +++ b/cmd/syft/internal/options/catalog_test.go @@ -70,3 +70,69 @@ func TestCatalog_PostLoad(t *testing.T) { }) } } + +func Test_enrichmentEnabled(t *testing.T) { + tests := []struct { + directives string + test string + expected *bool + }{ + { + directives: "", + test: "java", + expected: nil, + }, + { + directives: "none", + test: "java", + expected: ptr(false), + }, + { + directives: "none,+java", + test: "java", + expected: ptr(true), + }, + { + directives: "all,none", + test: "java", + expected: ptr(false), + }, + { + directives: "all", + test: "java", + expected: ptr(true), + }, + { + directives: "golang,js", + test: "java", + expected: nil, + }, + { + directives: "golang,-js,java", + test: "java", + expected: ptr(true), + }, + { + directives: "golang,js,-java", + test: "java", + expected: ptr(false), + }, + { + directives: "on", + test: "java", + expected: ptr(true), + }, + { + directives: "on,-java", + test: "java", + expected: ptr(false), + }, + } + + for _, test := range tests { + t.Run(test.directives, func(t *testing.T) { + got := enrichmentEnabled(flatten([]string{test.directives}), test.test) + assert.Equal(t, test.expected, got) + }) + } +} diff --git a/cmd/syft/internal/options/network.go b/cmd/syft/internal/options/network.go deleted file mode 100644 index a2946d23ff2..00000000000 --- a/cmd/syft/internal/options/network.go +++ /dev/null @@ -1,82 +0,0 @@ -package options - -import ( - "strings" - - "github.com/anchore/clio" - "github.com/anchore/fangs" - "github.com/anchore/syft/internal/log" -) - -type Network struct { - Enable []string `yaml:"enable" json:"enable" mapstructure:"enable"` -} - -func (n *Network) PostLoad() error { - n.Enable = flatten(n.Enable) - return nil -} - -func (n *Network) AddFlags(flags clio.FlagSet) { - flags.StringArrayVarP(&n.Enable, "network", "", - "enable features to use the network to fetch and augment package information") -} - -func (n *Network) Enabled(features ...string) *bool { - if n == nil { - return nil - } - return networkEnabled(n.Enable, features...) -} - -var _ interface { - fangs.PostLoader - fangs.FlagAdder -} = (*Network)(nil) - -func networkEnabled(networkDirectives []string, features ...string) *bool { - if len(networkDirectives) == 0 { - return nil - } - - enabled := func(features ...string) *bool { - for _, directive := range networkDirectives { - enable := true - directive = strings.TrimPrefix(directive, "+") // +java and java are equivalent - if strings.HasPrefix(directive, "-") { - directive = directive[1:] - enable = false - } - for _, feature := range features { - if directive == feature { - return &enable - } - } - } - return nil - } - - enableAll := enabled("all", "yes", "on", "enable", "enabled") - disableAll := enabled("none", "no", "off", "disable", "disabled") - - if disableAll != nil { - if enableAll != nil { - log.Warn("you have specified to both enable and disable all network functionality, defaulting to disabled") - } - enableAll = ptr(!*disableAll) - } - - // check for explicit enable/disable of feature names - for _, feat := range features { - enableFeature := enabled(feat) - if enableFeature != nil { - return enableFeature - } - } - - return enableAll -} - -func ptr[T any](val T) *T { - return &val -} diff --git a/cmd/syft/internal/options/network_test.go b/cmd/syft/internal/options/network_test.go deleted file mode 100644 index 593f48f8251..00000000000 --- a/cmd/syft/internal/options/network_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package options - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func Test_networkEnabled(t *testing.T) { - tests := []struct { - directives string - test string - expected *bool - }{ - { - directives: "", - test: "java", - expected: nil, - }, - { - directives: "none", - test: "java", - expected: ptr(false), - }, - { - directives: "none,+java", - test: "java", - expected: ptr(true), - }, - { - directives: "all,none", - test: "java", - expected: ptr(false), - }, - { - directives: "all", - test: "java", - expected: ptr(true), - }, - { - directives: "golang,js", - test: "java", - expected: nil, - }, - { - directives: "golang,-js,java", - test: "java", - expected: ptr(true), - }, - { - directives: "golang,js,-java", - test: "java", - expected: ptr(false), - }, - { - directives: "on", - test: "java", - expected: ptr(true), - }, - { - directives: "on,-java", - test: "java", - expected: ptr(false), - }, - } - - for _, test := range tests { - t.Run(test.directives, func(t *testing.T) { - n := Network{ - Enable: []string{test.directives}, - } - require.NoError(t, n.PostLoad()) - - got := n.Enabled(test.test) - require.Equal(t, test.expected, got) - }) - } -} diff --git a/cmd/syft/internal/options/update_check.go b/cmd/syft/internal/options/update_check.go index 5abae032193..0f396a5d9fc 100644 --- a/cmd/syft/internal/options/update_check.go +++ b/cmd/syft/internal/options/update_check.go @@ -3,15 +3,13 @@ package options import "github.com/anchore/fangs" type UpdateCheck struct { - CheckForAppUpdate *bool `yaml:"check-for-app-update" json:"check-for-app-update" mapstructure:"check-for-app-update"` // whether to check for an application update on start up or not + CheckForAppUpdate bool `yaml:"check-for-app-update" json:"check-for-app-update" mapstructure:"check-for-app-update"` // whether to check for an application update on start up or not } func DefaultUpdateCheck() UpdateCheck { - return UpdateCheck{} -} - -func (cfg *UpdateCheck) DoCheckForAppUpdate(net *Network) bool { - return *multiLevelOption(true, net.Enabled("update-check"), cfg.CheckForAppUpdate) + return UpdateCheck{ + CheckForAppUpdate: true, + } } func (cfg *UpdateCheck) DescribeFields(descriptions fangs.FieldDescriptionSet) { diff --git a/internal/task/executor.go b/internal/task/executor.go index 899796424be..2935f61b12c 100644 --- a/internal/task/executor.go +++ b/internal/task/executor.go @@ -7,9 +7,9 @@ import ( "sync" "time" + "github.com/anchore/syft/internal/log" "github.com/hashicorp/go-multierror" - "github.com/anchore/syft/internal/log" "github.com/anchore/syft/internal/sbomsync" "github.com/anchore/syft/syft/event/monitor" "github.com/anchore/syft/syft/file" From 48b62534a8664bb736b44ca11623435f8cd65fad Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Fri, 6 Sep 2024 14:35:43 -0400 Subject: [PATCH 10/15] chore: update tests Signed-off-by: Keith Zantow --- cmd/syft/internal/options/catalog_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/syft/internal/options/catalog_test.go b/cmd/syft/internal/options/catalog_test.go index a9b730fdacb..cf02630bf64 100644 --- a/cmd/syft/internal/options/catalog_test.go +++ b/cmd/syft/internal/options/catalog_test.go @@ -118,12 +118,12 @@ func Test_enrichmentEnabled(t *testing.T) { expected: ptr(false), }, { - directives: "on", + directives: "all", test: "java", expected: ptr(true), }, { - directives: "on,-java", + directives: "all,-java", test: "java", expected: ptr(false), }, From ebbd872f4771cb6e7b76e03f597ade1a07add09d Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Mon, 9 Sep 2024 14:58:04 -0400 Subject: [PATCH 11/15] chore: update cleanup-cache to run only on main repo Signed-off-by: Keith Zantow --- .github/workflows/validations.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validations.yaml b/.github/workflows/validations.yaml index 0ebca5c8235..9caeaae84ce 100644 --- a/.github/workflows/validations.yaml +++ b/.github/workflows/validations.yaml @@ -206,7 +206,7 @@ jobs: Cleanup-Cache: name: "Cleanup snapshot cache" - if: always() + if: github.repository == 'anchore/syft' runs-on: ubuntu-20.04 permissions: actions: write From 1f24f17aa1bb8ac9765f571afaaa3dcd77208f81 Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Mon, 9 Sep 2024 15:17:09 -0400 Subject: [PATCH 12/15] chore: correct cleanup-cache to run only on main repo Signed-off-by: Keith Zantow --- .github/workflows/validations.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validations.yaml b/.github/workflows/validations.yaml index 9caeaae84ce..0413e16371a 100644 --- a/.github/workflows/validations.yaml +++ b/.github/workflows/validations.yaml @@ -206,7 +206,7 @@ jobs: Cleanup-Cache: name: "Cleanup snapshot cache" - if: github.repository == 'anchore/syft' + if: github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-20.04 permissions: actions: write From 8da8f11fc6dbb95436f937696682d41b3ce2498a Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Wed, 11 Sep 2024 17:16:11 -0400 Subject: [PATCH 13/15] chore: export cataloger name constants to match enrich Signed-off-by: Keith Zantow --- cmd/syft/internal/options/catalog.go | 7 ++++--- internal/task/package_tasks.go | 31 +++++++++++++++++++++------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/cmd/syft/internal/options/catalog.go b/cmd/syft/internal/options/catalog.go index 44ba7b2cf74..259e75dca75 100644 --- a/cmd/syft/internal/options/catalog.go +++ b/cmd/syft/internal/options/catalog.go @@ -11,6 +11,7 @@ import ( "github.com/anchore/fangs" intFile "github.com/anchore/syft/internal/file" "github.com/anchore/syft/internal/log" + "github.com/anchore/syft/internal/task" "github.com/anchore/syft/syft" "github.com/anchore/syft/syft/cataloging" "github.com/anchore/syft/syft/cataloging/filecataloging" @@ -133,7 +134,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { Golang: golang.DefaultCatalogerConfig(). WithSearchLocalModCacheLicenses(cfg.Golang.SearchLocalModCacheLicenses). WithLocalModCacheDir(cfg.Golang.LocalModCacheDir). - WithSearchRemoteLicenses(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, "golang", "go"), cfg.Golang.SearchRemoteLicenses)). + WithSearchRemoteLicenses(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, task.Go, task.Golang), cfg.Golang.SearchRemoteLicenses)). WithProxy(cfg.Golang.Proxy). WithNoProxy(cfg.Golang.NoProxy). WithMainModuleVersion( @@ -143,7 +144,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { WithFromLDFlags(cfg.Golang.MainModuleVersion.FromLDFlags), ), JavaScript: javascript.DefaultCatalogerConfig(). - WithSearchRemoteLicenses(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, "javascript", "js"), cfg.JavaScript.SearchRemoteLicenses)). + WithSearchRemoteLicenses(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, task.JavaScript, task.Node, task.NPM), cfg.JavaScript.SearchRemoteLicenses)). WithNpmBaseURL(cfg.JavaScript.NpmBaseURL), LinuxKernel: kernel.LinuxKernelCatalogerConfig{ CatalogModules: cfg.LinuxKernel.CatalogModules, @@ -154,7 +155,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { JavaArchive: java.DefaultArchiveCatalogerConfig(). WithUseMavenLocalRepository(cfg.Java.UseMavenLocalRepository). WithMavenLocalRepositoryDir(cfg.Java.MavenLocalRepositoryDir). - WithUseNetwork(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, "java", "maven"), cfg.Java.UseNetwork)). + WithUseNetwork(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, task.Java, task.Maven), cfg.Java.UseNetwork)). WithMavenBaseURL(cfg.Java.MavenURL). WithArchiveTraversal(archiveSearch, cfg.Java.MaxParentRecursiveDepth), } diff --git a/internal/task/package_tasks.go b/internal/task/package_tasks.go index 4d56dc88adc..14eaf4044ae 100644 --- a/internal/task/package_tasks.go +++ b/internal/task/package_tasks.go @@ -34,6 +34,21 @@ import ( "github.com/anchore/syft/syft/pkg/cataloger/wordpress" ) +const ( + // Java ecosystem labels + Java = "java" + Maven = "maven" + + // Go language ecosystem labels + Go = "go" + Golang = "golang" + + // JavaScript ecosystem labels + JavaScript = "javascript" + Node = "node" + NPM = "npm" +) + //nolint:funlen func DefaultPackageTaskFactories() PackageTaskFactories { return []packageTaskFactory{ @@ -49,7 +64,7 @@ func DefaultPackageTaskFactories() PackageTaskFactories { // language-specific package installed catalogers /////////////////////////////////////////////////////////////////////////// newSimplePackageTaskFactory(cpp.NewConanInfoCataloger, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "cpp", "conan"), - newSimplePackageTaskFactory(javascript.NewPackageCataloger, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "javascript", "node"), + newSimplePackageTaskFactory(javascript.NewPackageCataloger, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, JavaScript, Node), newSimplePackageTaskFactory(php.NewComposerInstalledCataloger, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "php", "composer"), newSimplePackageTaskFactory(r.NewPackageCataloger, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "r"), newSimplePackageTaskFactory(ruby.NewInstalledGemSpecCataloger, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "ruby", "gem", "gemspec"), @@ -67,20 +82,20 @@ func DefaultPackageTaskFactories() PackageTaskFactories { func(cfg CatalogingFactoryConfig) pkg.Cataloger { return golang.NewGoModuleFileCataloger(cfg.PackagesConfig.Golang) }, - pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, "go", "golang", "gomod", + pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, Go, Golang, "gomod", ), - newSimplePackageTaskFactory(java.NewGradleLockfileCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, "java", "gradle"), + newSimplePackageTaskFactory(java.NewGradleLockfileCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, Java, "gradle"), newPackageTaskFactory( func(cfg CatalogingFactoryConfig) pkg.Cataloger { return java.NewPomCataloger(cfg.PackagesConfig.JavaArchive) }, - pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, "java", "maven", + pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, Java, Maven, ), newPackageTaskFactory( func(cfg CatalogingFactoryConfig) pkg.Cataloger { return javascript.NewLockCataloger(cfg.PackagesConfig.JavaScript) }, - pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, "javascript", "node", "npm", + pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, JavaScript, Node, NPM, ), newSimplePackageTaskFactory(php.NewComposerLockCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, "php", "composer"), newSimplePackageTaskFactory(php.NewPeclCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, pkgcataloging.ImageTag, "php", "pecl"), @@ -105,15 +120,15 @@ func DefaultPackageTaskFactories() PackageTaskFactories { func(cfg CatalogingFactoryConfig) pkg.Cataloger { return golang.NewGoModuleBinaryCataloger(cfg.PackagesConfig.Golang) }, - pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "go", "golang", "gomod", "binary", + pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, Go, Golang, "gomod", "binary", ), newPackageTaskFactory( func(cfg CatalogingFactoryConfig) pkg.Cataloger { return java.NewArchiveCataloger(cfg.PackagesConfig.JavaArchive) }, - pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "java", "maven", + pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, Java, Maven, ), - newSimplePackageTaskFactory(java.NewNativeImageCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "java"), + newSimplePackageTaskFactory(java.NewNativeImageCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, Java), newSimplePackageTaskFactory(nix.NewStoreCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "nix"), newSimplePackageTaskFactory(lua.NewPackageCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "lua"), From 13a45ed315e9aca1fac09a5e063803216680641f Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Wed, 11 Sep 2024 17:30:20 -0400 Subject: [PATCH 14/15] fix: add local filesystem to enrichment options Signed-off-by: Keith Zantow --- cmd/syft/internal/options/catalog.go | 4 ++-- cmd/syft/internal/options/golang.go | 4 ++-- cmd/syft/internal/options/java.go | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmd/syft/internal/options/catalog.go b/cmd/syft/internal/options/catalog.go index 259e75dca75..661f9fbe32b 100644 --- a/cmd/syft/internal/options/catalog.go +++ b/cmd/syft/internal/options/catalog.go @@ -132,7 +132,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { return pkgcataloging.Config{ Binary: binary.DefaultClassifierCatalogerConfig(), Golang: golang.DefaultCatalogerConfig(). - WithSearchLocalModCacheLicenses(cfg.Golang.SearchLocalModCacheLicenses). + WithSearchLocalModCacheLicenses(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, task.Go, task.Golang), cfg.Golang.SearchLocalModCacheLicenses)). WithLocalModCacheDir(cfg.Golang.LocalModCacheDir). WithSearchRemoteLicenses(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, task.Go, task.Golang), cfg.Golang.SearchRemoteLicenses)). WithProxy(cfg.Golang.Proxy). @@ -153,7 +153,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { GuessUnpinnedRequirements: cfg.Python.GuessUnpinnedRequirements, }, JavaArchive: java.DefaultArchiveCatalogerConfig(). - WithUseMavenLocalRepository(cfg.Java.UseMavenLocalRepository). + WithUseMavenLocalRepository(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, task.Java, task.Maven), cfg.Java.UseMavenLocalRepository)). WithMavenLocalRepositoryDir(cfg.Java.MavenLocalRepositoryDir). WithUseNetwork(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, task.Java, task.Maven), cfg.Java.UseNetwork)). WithMavenBaseURL(cfg.Java.MavenURL). diff --git a/cmd/syft/internal/options/golang.go b/cmd/syft/internal/options/golang.go index d8073275928..59fe421fe56 100644 --- a/cmd/syft/internal/options/golang.go +++ b/cmd/syft/internal/options/golang.go @@ -8,7 +8,7 @@ import ( ) type golangConfig struct { - SearchLocalModCacheLicenses bool `json:"search-local-mod-cache-licenses" yaml:"search-local-mod-cache-licenses" mapstructure:"search-local-mod-cache-licenses"` + SearchLocalModCacheLicenses *bool `json:"search-local-mod-cache-licenses" yaml:"search-local-mod-cache-licenses" mapstructure:"search-local-mod-cache-licenses"` LocalModCacheDir string `json:"local-mod-cache-dir" yaml:"local-mod-cache-dir" mapstructure:"local-mod-cache-dir"` SearchRemoteLicenses *bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"` Proxy string `json:"proxy" yaml:"proxy" mapstructure:"proxy"` @@ -47,7 +47,7 @@ type golangMainModuleVersionConfig struct { func defaultGolangConfig() golangConfig { def := golang.DefaultCatalogerConfig() return golangConfig{ - SearchLocalModCacheLicenses: def.SearchLocalModCacheLicenses, + SearchLocalModCacheLicenses: nil, // this defaults to false, which is the API default LocalModCacheDir: def.LocalModCacheDir, SearchRemoteLicenses: nil, // this defaults to false, which is the API default Proxy: strings.Join(def.Proxies, ","), diff --git a/cmd/syft/internal/options/java.go b/cmd/syft/internal/options/java.go index ab381a3917e..6244de44fab 100644 --- a/cmd/syft/internal/options/java.go +++ b/cmd/syft/internal/options/java.go @@ -7,7 +7,7 @@ import ( type javaConfig struct { UseNetwork *bool `yaml:"use-network" json:"use-network" mapstructure:"use-network"` - UseMavenLocalRepository bool `yaml:"use-maven-local-repository" json:"use-maven-local-repository" mapstructure:"use-maven-local-repository"` + UseMavenLocalRepository *bool `yaml:"use-maven-local-repository" json:"use-maven-local-repository" mapstructure:"use-maven-local-repository"` MavenLocalRepositoryDir string `yaml:"maven-local-repository-dir" json:"maven-local-repository-dir" mapstructure:"maven-local-repository-dir"` MavenURL string `yaml:"maven-url" json:"maven-url" mapstructure:"maven-url"` MaxParentRecursiveDepth int `yaml:"max-parent-recursive-depth" json:"max-parent-recursive-depth" mapstructure:"max-parent-recursive-depth"` @@ -17,9 +17,9 @@ func defaultJavaConfig() javaConfig { def := java.DefaultArchiveCatalogerConfig() return javaConfig{ - UseNetwork: nil, // this defaults to "false", which is the API default + UseNetwork: nil, // this defaults to false, which is the API default MaxParentRecursiveDepth: def.MaxParentRecursiveDepth, - UseMavenLocalRepository: def.UseMavenLocalRepository, + UseMavenLocalRepository: nil, // this defaults to false, which is the API default MavenLocalRepositoryDir: def.MavenLocalRepositoryDir, MavenURL: def.MavenBaseURL, } From 9fc66e9bf1c196c8e9d6ae887efa06776da91af9 Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Wed, 11 Sep 2024 22:55:36 -0400 Subject: [PATCH 15/15] chore: update CLI documentation Signed-off-by: Keith Zantow --- cmd/syft/internal/options/catalog.go | 22 +++++++++++++++------- internal/task/package_tasks.go | 2 +- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/cmd/syft/internal/options/catalog.go b/cmd/syft/internal/options/catalog.go index 661f9fbe32b..8d18518605e 100644 --- a/cmd/syft/internal/options/catalog.go +++ b/cmd/syft/internal/options/catalog.go @@ -57,7 +57,7 @@ type Catalog struct { var _ interface { clio.FlagAdder clio.PostLoader - fangs.FieldDescriber + clio.FieldDescriber } = (*Catalog)(nil) func DefaultCatalog() Catalog { @@ -196,7 +196,7 @@ func (cfg *Catalog) AddFlags(flags clio.FlagSet) { "add, remove, and filter the catalogers to be used") flags.StringArrayVarP(&cfg.Enrich, "enrich", "", - "enable data enrichment operations, which can utilize services such as Maven Central and NPM") + fmt.Sprintf("enable package data enrichment from local and online sources (options: %s)", strings.Join(publicisedEnrichmentOptions, ", "))) flags.StringVarP(&cfg.Source.Name, "source-name", "", "set the name of the target being analyzed") @@ -211,8 +211,9 @@ func (cfg *Catalog) AddFlags(flags clio.FlagSet) { func (cfg *Catalog) DescribeFields(descriptions fangs.FieldDescriptionSet) { descriptions.Add(&cfg.Parallelism, "number of cataloger workers to run in parallel") - descriptions.Add(&cfg.Enrich, `enable/disable data enrichment operations. By default all enrichment is disabled, use: all to enable everything. -Prefixing with a minus will remove the enrichment, e.g. enrich: [all, -java] would enable all except java enrichment. `) + descriptions.Add(&cfg.Enrich, fmt.Sprintf(`Enable data enrichment operations, which can utilize services such as Maven Central and NPM. +By default all enrichment is disabled, use: all to enable everything. +Available options are: %s`, strings.Join(publicisedEnrichmentOptions, ", "))) } func (cfg *Catalog) PostLoad() error { @@ -252,6 +253,13 @@ func flatten(commaSeparatedEntries []string) []string { return out } +var publicisedEnrichmentOptions = []string{ + "all", + task.Golang, + task.Java, + task.JavaScript, +} + func enrichmentEnabled(enrichDirectives []string, features ...string) *bool { if len(enrichDirectives) == 0 { return nil @@ -277,11 +285,11 @@ func enrichmentEnabled(enrichDirectives []string, features ...string) *bool { enableAll := enabled("all") disableAll := enabled("none") - if disableAll != nil { + if disableAll != nil && *disableAll { if enableAll != nil { - log.Warn("you have specified to both enable and disable all network functionality, defaulting to disabled") + log.Warn("you have specified to both enable and disable all enrichment functionality, defaulting to disabled") } - enableAll = ptr(!*disableAll) + enableAll = ptr(false) } // check for explicit enable/disable of feature names diff --git a/internal/task/package_tasks.go b/internal/task/package_tasks.go index 14eaf4044ae..c38299f4dd6 100644 --- a/internal/task/package_tasks.go +++ b/internal/task/package_tasks.go @@ -39,7 +39,7 @@ const ( Java = "java" Maven = "maven" - // Go language ecosystem labels + // Go ecosystem labels Go = "go" Golang = "golang"