diff --git a/cmd/syft/internal/options/catalog.go b/cmd/syft/internal/options/catalog.go index 870b02507..599af87f2 100644 --- a/cmd/syft/internal/options/catalog.go +++ b/cmd/syft/internal/options/catalog.go @@ -19,6 +19,7 @@ import ( "github.com/anchore/syft/syft/file/cataloger/executable" "github.com/anchore/syft/syft/file/cataloger/filecontent" "github.com/anchore/syft/syft/pkg/cataloger/binary" + "github.com/anchore/syft/syft/pkg/cataloger/dotnet" "github.com/anchore/syft/syft/pkg/cataloger/golang" "github.com/anchore/syft/syft/pkg/cataloger/java" "github.com/anchore/syft/syft/pkg/cataloger/javascript" @@ -42,6 +43,7 @@ type Catalog struct { Enrich []string `yaml:"enrich" json:"enrich" mapstructure:"enrich"` // ecosystem-specific cataloger configuration + Dotnet dotnetConfig `yaml:"dotnet" json:"dotnet" mapstructure:"dotnet"` Golang golangConfig `yaml:"golang" json:"golang" mapstructure:"golang"` Java javaConfig `yaml:"java" json:"java" mapstructure:"java"` JavaScript javaScriptConfig `yaml:"javascript" json:"javascript" mapstructure:"javascript"` @@ -72,6 +74,7 @@ func DefaultCatalog() Catalog { Package: defaultPackageConfig(), License: defaultLicenseConfig(), LinuxKernel: defaultLinuxKernelConfig(), + Dotnet: defaultDotnetConfig(), Golang: defaultGolangConfig(), Java: defaultJavaConfig(), File: defaultFileConfig(), @@ -163,6 +166,8 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config { } return pkgcataloging.Config{ Binary: binary.DefaultClassifierCatalogerConfig(), + Dotnet: dotnet.DefaultCatalogerConfig(). + WithCertificateValidation(cfg.Dotnet.EnableCertificateValidation), Golang: golang.DefaultCatalogerConfig(). WithSearchLocalModCacheLicenses(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, task.Go, task.Golang), cfg.Golang.SearchLocalModCacheLicenses)). WithLocalModCacheDir(cfg.Golang.LocalModCacheDir). diff --git a/cmd/syft/internal/options/dotnet.go b/cmd/syft/internal/options/dotnet.go new file mode 100644 index 000000000..6d7c1ba1a --- /dev/null +++ b/cmd/syft/internal/options/dotnet.go @@ -0,0 +1,25 @@ +package options + +import ( + "github.com/anchore/clio" + "github.com/anchore/syft/syft/pkg/cataloger/dotnet" +) + +type dotnetConfig struct { + EnableCertificateValidation bool `json:"enable-certificate-validation" yaml:"enable-certificate-validation" mapstructure:"enable-certificate-validation"` +} + +var _ interface { + clio.FieldDescriber +} = (*dotnetConfig)(nil) + +func (o *dotnetConfig) DescribeFields(descriptions clio.FieldDescriptionSet) { + descriptions.Add(&o.EnableCertificateValidation, `enable certificate validation -- this requires an active internet connection to download certificates and CRLs`) +} + +func defaultDotnetConfig() dotnetConfig { + def := dotnet.DefaultCatalogerConfig() + return dotnetConfig{ + EnableCertificateValidation: def.EnableCertificateValidation, + } +} diff --git a/internal/task/package_tasks.go b/internal/task/package_tasks.go index 64a3e476c..a709789ce 100644 --- a/internal/task/package_tasks.go +++ b/internal/task/package_tasks.go @@ -117,7 +117,10 @@ func DefaultPackageTaskFactories() Factories { // language-specific package for both image and directory scans (but not necessarily declared) //////////////////////////////////////// newSimplePackageTaskFactory(dotnet.NewDotnetPackagesLockCataloger, pkgcataloging.DeclaredTag, pkgcataloging.ImageTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, "dotnet", "c#"), - newSimplePackageTaskFactory(dotnet.NewDotnetPortableExecutableCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "dotnet", "c#", "binary"), + newPackageTaskFactory( + func(cfg CatalogingFactoryConfig) pkg.Cataloger { + return dotnet.NewDotnetPortableExecutableCataloger(cfg.PackagesConfig.Dotnet) + }, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "dotnet", "c#", "binary"), newSimplePackageTaskFactory(python.NewInstalledPackageCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "python"), newPackageTaskFactory( func(cfg CatalogingFactoryConfig) pkg.Cataloger { diff --git a/syft/cataloging/pkgcataloging/config.go b/syft/cataloging/pkgcataloging/config.go index ac55de7ef..1139285ec 100644 --- a/syft/cataloging/pkgcataloging/config.go +++ b/syft/cataloging/pkgcataloging/config.go @@ -2,6 +2,7 @@ package pkgcataloging import ( "github.com/anchore/syft/syft/pkg/cataloger/binary" + "github.com/anchore/syft/syft/pkg/cataloger/dotnet" "github.com/anchore/syft/syft/pkg/cataloger/golang" "github.com/anchore/syft/syft/pkg/cataloger/java" "github.com/anchore/syft/syft/pkg/cataloger/javascript" @@ -11,6 +12,7 @@ import ( type Config struct { Binary binary.ClassifierCatalogerConfig `yaml:"binary" json:"binary" mapstructure:"binary"` + Dotnet dotnet.CatalogerConfig `yaml:"dotnet" json:"dotnet" mapstructure:"dotnet"` Golang golang.CatalogerConfig `yaml:"golang" json:"golang" mapstructure:"golang"` JavaArchive java.ArchiveCatalogerConfig `yaml:"java-archive" json:"java-archive" mapstructure:"java-archive"` JavaScript javascript.CatalogerConfig `yaml:"javascript" json:"javascript" mapstructure:"javascript"` @@ -21,6 +23,7 @@ type Config struct { func DefaultConfig() Config { return Config{ Binary: binary.DefaultClassifierCatalogerConfig(), + Dotnet: dotnet.DefaultCatalogerConfig(), Golang: golang.DefaultCatalogerConfig(), LinuxKernel: kernel.DefaultLinuxKernelCatalogerConfig(), Python: python.DefaultCatalogerConfig(), @@ -33,6 +36,11 @@ func (c Config) WithBinaryConfig(cfg binary.ClassifierCatalogerConfig) Config { return c } +func (c Config) WithDotnetConfig(cfg dotnet.CatalogerConfig) Config { + c.Dotnet = cfg + return c +} + func (c Config) WithGolangConfig(cfg golang.CatalogerConfig) Config { c.Golang = cfg return c diff --git a/syft/pkg/cataloger/dotnet/cataloger.go b/syft/pkg/cataloger/dotnet/cataloger.go index 2257e3d86..569fcb49d 100644 --- a/syft/pkg/cataloger/dotnet/cataloger.go +++ b/syft/pkg/cataloger/dotnet/cataloger.go @@ -15,9 +15,10 @@ func NewDotnetDepsCataloger() pkg.Cataloger { } // NewDotnetPortableExecutableCataloger returns a new Dotnet cataloger object base on portable executable files. -func NewDotnetPortableExecutableCataloger() pkg.Cataloger { +func NewDotnetPortableExecutableCataloger(cfg CatalogerConfig) pkg.Cataloger { + p := dotnetPortableExecutableParser{cfg: cfg} return generic.NewCataloger("dotnet-portable-executable-cataloger"). - WithParserByGlobs(parseDotnetPortableExecutable, "**/*.dll", "**/*.exe") + WithParserByGlobs(p.parseDotnetPortableExecutable, "**/*.dll", "**/*.exe") } func NewDotnetPackagesLockCataloger() pkg.Cataloger { diff --git a/syft/pkg/cataloger/dotnet/cataloger_test.go b/syft/pkg/cataloger/dotnet/cataloger_test.go index 7817d2315..d2b3c5f89 100644 --- a/syft/pkg/cataloger/dotnet/cataloger_test.go +++ b/syft/pkg/cataloger/dotnet/cataloger_test.go @@ -25,7 +25,7 @@ func TestCataloger_Globs(t *testing.T) { { name: "obtain portable executable files", fixture: "test-fixtures/glob-paths", - cataloger: NewDotnetPortableExecutableCataloger(), + cataloger: NewDotnetPortableExecutableCataloger(DefaultCatalogerConfig()), expected: []string{ "src/something.dll", "src/something.exe", diff --git a/syft/pkg/cataloger/dotnet/config.go b/syft/pkg/cataloger/dotnet/config.go new file mode 100644 index 000000000..3c3712c8b --- /dev/null +++ b/syft/pkg/cataloger/dotnet/config.go @@ -0,0 +1,14 @@ +package dotnet + +type CatalogerConfig struct { + EnableCertificateValidation bool `json:"enable-certificate-validation" yaml:"enable-certificate-validation" mapstructure:"enable-certificate-validation"` +} + +func (c CatalogerConfig) WithCertificateValidation(enable bool) CatalogerConfig { + c.EnableCertificateValidation = enable + return c +} + +func DefaultCatalogerConfig() CatalogerConfig { + return CatalogerConfig{} +} diff --git a/syft/pkg/cataloger/dotnet/parse_dotnet_portable_executable.go b/syft/pkg/cataloger/dotnet/parse_dotnet_portable_executable.go index 4ea4d1c18..fbf5e860e 100644 --- a/syft/pkg/cataloger/dotnet/parse_dotnet_portable_executable.go +++ b/syft/pkg/cataloger/dotnet/parse_dotnet_portable_executable.go @@ -18,15 +18,17 @@ import ( "github.com/anchore/syft/syft/pkg/cataloger/generic" ) -var _ generic.Parser = parseDotnetPortableExecutable +type dotnetPortableExecutableParser struct { + cfg CatalogerConfig +} -func parseDotnetPortableExecutable(_ context.Context, _ file.Resolver, _ *generic.Environment, f file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { +func (p dotnetPortableExecutableParser) parseDotnetPortableExecutable(_ context.Context, _ file.Resolver, _ *generic.Environment, f file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { by, err := io.ReadAll(f) if err != nil { return nil, nil, fmt.Errorf("unable to read file: %w", err) } - peFile, err := pe.NewBytes(by, &pe.Options{}) + peFile, err := pe.NewBytes(by, &pe.Options{DisableCertValidation: !p.cfg.EnableCertificateValidation}) if err != nil { log.Tracef("unable to create PE instance for file '%s': %v", f.RealPath, err) return nil, nil, err diff --git a/syft/pkg/cataloger/dotnet/parse_dotnet_portable_executable_test.go b/syft/pkg/cataloger/dotnet/parse_dotnet_portable_executable_test.go index 2be417d6a..b92664e9b 100644 --- a/syft/pkg/cataloger/dotnet/parse_dotnet_portable_executable_test.go +++ b/syft/pkg/cataloger/dotnet/parse_dotnet_portable_executable_test.go @@ -298,10 +298,13 @@ func TestParseDotnetPortableExecutable(t *testing.T) { } func Test_corruptDotnetPE(t *testing.T) { + p := dotnetPortableExecutableParser{ + cfg: DefaultCatalogerConfig(), + } pkgtest.NewCatalogTester(). FromFile(t, "test-fixtures/glob-paths/src/something.exe"). WithError(). - TestParser(t, parseDotnetPortableExecutable) + TestParser(t, p.parseDotnetPortableExecutable) } func Test_extractVersion(t *testing.T) {