diff --git a/cmd/grype-db/cli/commands/build.go b/cmd/grype-db/cli/commands/build.go index 79dc6f73..43549901 100644 --- a/cmd/grype-db/cli/commands/build.go +++ b/cmd/grype-db/cli/commands/build.go @@ -109,11 +109,12 @@ func runBuild(cfg buildConfig) error { } return process.Build(process.BuildConfig{ - SchemaVersion: cfg.SchemaVersion, - Directory: cfg.Directory, - States: states, - Timestamp: earliestTimestamp(states), - IncludeCPEParts: cfg.IncludeCPEParts, + SchemaVersion: cfg.SchemaVersion, + Directory: cfg.Directory, + States: states, + Timestamp: earliestTimestamp(states), + IncludeCPEParts: cfg.IncludeCPEParts, + InferNVDFixVersions: cfg.InferNVDFixVersions, }) } diff --git a/cmd/grype-db/cli/options/build.go b/cmd/grype-db/cli/options/build.go index 1014dc5b..13b90c2b 100644 --- a/cmd/grype-db/cli/options/build.go +++ b/cmd/grype-db/cli/options/build.go @@ -17,15 +17,17 @@ type Build struct { SchemaVersion int `yaml:"schema-version" json:"schema-version" mapstructure:"schema-version"` // unbound options - IncludeCPEParts []string `yaml:"include-cpe-parts" json:"include-cpe-parts" mapstructure:"include-cpe-parts"` + IncludeCPEParts []string `yaml:"include-cpe-parts" json:"include-cpe-parts" mapstructure:"include-cpe-parts"` + InferNVDFixVersions bool `yaml:"infer-nvd-fix-versions" json:"infer-nvd-fix-versions" mapstructure:"infer-nvd-fix-versions"` } func DefaultBuild() Build { return Build{ - DBLocation: DefaultDBLocation(), - SkipValidation: false, - SchemaVersion: process.DefaultSchemaVersion, - IncludeCPEParts: []string{"a"}, + DBLocation: DefaultDBLocation(), + SkipValidation: false, + SchemaVersion: process.DefaultSchemaVersion, + IncludeCPEParts: []string{"a"}, + InferNVDFixVersions: true, } } @@ -56,6 +58,7 @@ func (o *Build) BindFlags(flags *pflag.FlagSet, v *viper.Viper) error { // set default values for non-bound struct items v.SetDefault("build.include-cpe-parts", o.IncludeCPEParts) + v.SetDefault("build.infer-nvd-fix-versions", o.InferNVDFixVersions) return o.DBLocation.BindFlags(flags, v) } diff --git a/pkg/process/build.go b/pkg/process/build.go index 12efe4ad..8a61fc1a 100644 --- a/pkg/process/build.go +++ b/pkg/process/build.go @@ -25,11 +25,12 @@ import ( ) type BuildConfig struct { - SchemaVersion int - Directory string - States provider.States - Timestamp time.Time - IncludeCPEParts []string + SchemaVersion int + Directory string + States provider.States + Timestamp time.Time + IncludeCPEParts []string + InferNVDFixVersions bool } func Build(cfg BuildConfig) error { @@ -101,7 +102,7 @@ func getProcessors(cfg BuildConfig) ([]data.Processor, error) { case grypeDBv4.SchemaVersion: return v4.Processors(), nil case grypeDBv5.SchemaVersion: - return v5.Processors(v5.NewConfig(v5.WithCPEParts(cfg.IncludeCPEParts))), nil + return v5.Processors(v5.NewConfig(v5.WithCPEParts(cfg.IncludeCPEParts), v5.WithInferNVDFixVersions(cfg.InferNVDFixVersions))), nil default: return nil, fmt.Errorf("unable to create processor: unsupported schema version: %+v", cfg.SchemaVersion) } diff --git a/pkg/process/v5/processors.go b/pkg/process/v5/processors.go index 238c812c..4a976bff 100644 --- a/pkg/process/v5/processors.go +++ b/pkg/process/v5/processors.go @@ -24,6 +24,12 @@ func WithCPEParts(included []string) Option { } } +func WithInferNVDFixVersions(infer bool) Option { + return func(cfg *Config) { + cfg.NVD.InferNVDFixVersions = infer + } +} + func NewConfig(options ...Option) Config { var cfg Config for _, option := range options { diff --git a/pkg/process/v5/transformers/nvd/transform.go b/pkg/process/v5/transformers/nvd/transform.go index 6cff6964..b78052a1 100644 --- a/pkg/process/v5/transformers/nvd/transform.go +++ b/pkg/process/v5/transformers/nvd/transform.go @@ -22,12 +22,14 @@ import ( ) type Config struct { - CPEParts *strset.Set + CPEParts *strset.Set + InferNVDFixVersions bool } func defaultConfig() Config { return Config{ - CPEParts: strset.New("a"), + CPEParts: strset.New("a"), + InferNVDFixVersions: true, } } @@ -91,7 +93,7 @@ func transform(cfg Config, vulnerability unmarshal.NVDVulnerability) ([]data.Ent PackageName: grypeNamespace.Resolver().Normalize(p.Product), Namespace: entryNamespace, CPEs: orderedCPEs, - Fix: getFix(matches), + Fix: getFix(matches, cfg.InferNVDFixVersions), }) } @@ -127,7 +129,13 @@ func getVersionFormat(name string, cpes []string) version.Format { return version.UnknownFormat } -func getFix(matches []nvd.CpeMatch) grypeDB.Fix { +func getFix(matches []nvd.CpeMatch, inferNVDFixVersions bool) grypeDB.Fix { + if !inferNVDFixVersions { + return grypeDB.Fix{ + State: grypeDB.UnknownFixState, + } + } + possiblyFixed := strset.New() knownAffected := strset.New() unspecifiedSet := strset.New("*", "-", "*") diff --git a/pkg/process/v5/transformers/nvd/transform_test.go b/pkg/process/v5/transformers/nvd/transform_test.go index 59e0a013..530094e0 100644 --- a/pkg/process/v5/transformers/nvd/transform_test.go +++ b/pkg/process/v5/transformers/nvd/transform_test.go @@ -1061,8 +1061,16 @@ func TestGetFix(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - fix := getFix(tt.matches) + fix := getFix(tt.matches, true) assert.Equal(t, tt.expected, fix) }) + + t.Run(tt.name+" don't infer NVD fixes", func(t *testing.T) { + fix := getFix(tt.matches, false) + assert.Equal(t, grypeDB.Fix{ + Versions: nil, + State: "unknown", + }, fix) + }) } }