From cdea96c222833579d863809d3390a156bf4446ab Mon Sep 17 00:00:00 2001 From: Josie Anugerah Date: Fri, 26 Apr 2024 15:40:13 +1000 Subject: [PATCH 1/7] implement filtering by packages using config files --- fixtures/testdatainner/osv-scanner.toml | 7 ++ pkg/config/config.go | 44 +++++++-- pkg/config/config_internal_test.go | 124 ++++++++++++++++++++++++ pkg/osvscanner/osvscanner.go | 13 +++ 4 files changed, 182 insertions(+), 6 deletions(-) diff --git a/fixtures/testdatainner/osv-scanner.toml b/fixtures/testdatainner/osv-scanner.toml index 1f843b60e6..d15175861a 100644 --- a/fixtures/testdatainner/osv-scanner.toml +++ b/fixtures/testdatainner/osv-scanner.toml @@ -7,3 +7,10 @@ id = "GO-2022-0968" id = "GO-2022-1059" # ignore_until = 2022-11-09 # Optional exception expiry date # reason = "" # Optional reason + +[[IgnoredPackageVersions]] +name = "lib" +version = "1.0.0" +ecosystem = "Go" +# ignore_until = 2022-11-09 # Optional exception expiry date +reason = "abc" diff --git a/pkg/config/config.go b/pkg/config/config.go index ddd660856a..b1f766dad2 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -23,9 +23,10 @@ type ConfigManager struct { } type Config struct { - IgnoredVulns []IgnoreEntry `toml:"IgnoredVulns"` - LoadPath string `toml:"LoadPath"` - GoVersionOverride string `toml:"GoVersionOverride"` + IgnoredVulns []IgnoreEntry `toml:"IgnoredVulns"` + IgnoredPackageVersions []IgnorePackageVersionEntry `toml:"IgnoredPackageVersions"` + LoadPath string `toml:"LoadPath"` + GoVersionOverride string `toml:"GoVersionOverride"` } type IgnoreEntry struct { @@ -34,19 +35,50 @@ type IgnoreEntry struct { Reason string `toml:"reason"` } +type IgnorePackageVersionEntry struct { + Name string `json:"name"` + Version string `json:"version"` // Q: If empty all versions of the package are ignored? + Ecosystem string `json:"ecosystem"` + // TODO: Commit? Should we use models.PackageInfo? Or keep this config + // decoupled from that model. I lean towards keeping it decoupled. + IgnoreUntil time.Time `toml:"ignoreUntil"` + Reason string `toml:"reason"` +} + func (c *Config) ShouldIgnore(vulnID string) (bool, IgnoreEntry) { index := slices.IndexFunc(c.IgnoredVulns, func(elem IgnoreEntry) bool { return elem.ID == vulnID }) if index == -1 { return false, IgnoreEntry{} } ignoredLine := c.IgnoredVulns[index] - if ignoredLine.IgnoreUntil.IsZero() { + + return shouldIgnoreTimestamp(ignoredLine.IgnoreUntil), ignoredLine +} + +func (c *Config) ShouldIgnorePackageVersion(name, version, ecosystem string) (bool, IgnorePackageVersionEntry) { + index := slices.IndexFunc(c.IgnoredPackageVersions, func(elem IgnorePackageVersionEntry) bool { + if name != elem.Name { + return false + } + + return version == elem.Version || elem.Version == "" + }) + if index == -1 { + return false, IgnorePackageVersionEntry{} + } + ignoredLine := c.IgnoredPackageVersions[index] + + return shouldIgnoreTimestamp(ignoredLine.IgnoreUntil), ignoredLine +} + +func shouldIgnoreTimestamp(ignoreUntil time.Time) bool { + if ignoreUntil.IsZero() { // If IgnoreUntil is not set, should ignore. - return true, ignoredLine + return true } // Should ignore if IgnoreUntil is still after current time // Takes timezone offsets into account if it is specified. otherwise it's using local time - return ignoredLine.IgnoreUntil.After(time.Now()), ignoredLine + return ignoreUntil.After(time.Now()) } // Sets the override config by reading the config file at configPath. diff --git a/pkg/config/config_internal_test.go b/pkg/config/config_internal_test.go index e271543f77..c266b911cb 100644 --- a/pkg/config/config_internal_test.go +++ b/pkg/config/config_internal_test.go @@ -27,6 +27,14 @@ func TestTryLoadConfig(t *testing.T) { ID: "GO-2022-1059", }, }, + IgnoredPackageVersions: []IgnorePackageVersionEntry{ + { + Name: "lib", + Version: "1.0.0", + Ecosystem: "Go", + Reason: "abc", + }, + }, } testPaths := []testStruct{ { @@ -69,6 +77,9 @@ func TestTryLoadConfig(t *testing.T) { if !cmp.Equal(config.IgnoredVulns, testData.config.IgnoredVulns) { t.Errorf("Configs not equal: %+v != %+v", config, testData.config) } + if !cmp.Equal(config.IgnoredPackageVersions, testData.config.IgnoredPackageVersions) { + t.Errorf("Configs not equal: %+v != %+v", config, testData.config) + } if testData.configHasErr { if configErr == nil { t.Error("Config error not returned") @@ -191,3 +202,116 @@ func TestConfig_ShouldIgnore(t *testing.T) { }) } } + +func TestConfig_ShouldIgnorePackageVersion(t *testing.T) { + t.Parallel() + + type args struct { + name string + version string + ecosystem string + } + tests := []struct { + name string + config Config + args args + wantOk bool + wantEntry IgnorePackageVersionEntry + }{ + { + name: "Version-level entry exists", + config: Config{ + IgnoredPackageVersions: []IgnorePackageVersionEntry{ + { + Name: "lib1", + Version: "1.0.0", + Ecosystem: "Go", + IgnoreUntil: time.Time{}, + Reason: "abc", + }, + }, + }, + args: args{ + name: "lib1", + version: "1.0.0", + ecosystem: "Go", + }, + wantOk: true, + wantEntry: IgnorePackageVersionEntry{ + Name: "lib1", + Version: "1.0.0", + Ecosystem: "Go", + IgnoreUntil: time.Time{}, + Reason: "abc", + }, + }, + { + name: "Package-level entry exists", + config: Config{ + IgnoredPackageVersions: []IgnorePackageVersionEntry{ + { + Name: "lib1", + Ecosystem: "Go", + IgnoreUntil: time.Time{}, + Reason: "abc", + }, + }, + }, + args: args{ + name: "lib1", + version: "1.0.0", + ecosystem: "Go", + }, + wantOk: true, + wantEntry: IgnorePackageVersionEntry{ + Name: "lib1", + Ecosystem: "Go", + IgnoreUntil: time.Time{}, + Reason: "abc", + }, + }, + { + name: "Entry doesn't exists", + config: Config{ + IgnoredPackageVersions: []IgnorePackageVersionEntry{ + { + Name: "lib1", + Version: "1.0.0", + Ecosystem: "Go", + IgnoreUntil: time.Time{}, + Reason: "abc", + }, + { + Name: "lib2", + Version: "2.0.0", + Ecosystem: "Go", + IgnoreUntil: time.Time{}, + Reason: "abc", + }, + }, + }, + args: args{ + name: "lib1", + version: "2.0.0", + ecosystem: "Go", + }, + wantOk: false, + wantEntry: IgnorePackageVersionEntry{}, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + gotOk, gotEntry := tt.config.ShouldIgnorePackageVersion(tt.args.name, tt.args.version, tt.args.ecosystem) + if gotOk != tt.wantOk { + t.Errorf("ShouldIgnorePackageVersion() gotOk = %v, wantOk %v", gotOk, tt.wantOk) + } + if !reflect.DeepEqual(gotEntry, tt.wantEntry) { + t.Errorf("ShouldIgnorePackageVersion() gotEntry = %v, wantEntry %v", gotEntry, tt.wantEntry) + } + }) + } +} diff --git a/pkg/osvscanner/osvscanner.go b/pkg/osvscanner/osvscanner.go index 7b4ace483e..172ec89582 100644 --- a/pkg/osvscanner/osvscanner.go +++ b/pkg/osvscanner/osvscanner.go @@ -639,6 +639,19 @@ func filterResults(r reporter.Reporter, results *models.VulnerabilityResults, co // Filters package-grouped vulnerabilities according to config, preserving ordering. Returns filtered package vulnerabilities. func filterPackageVulns(r reporter.Reporter, pkgVulns models.PackageVulns, configToUse config.Config) models.PackageVulns { + if ignore, ignoreLine := configToUse.ShouldIgnorePackageVersion(pkgVulns.Package.Name, pkgVulns.Package.Version, pkgVulns.Package.Ecosystem); ignore { + pkgString := fmt.Sprintf("%s/%s/%s", pkgVulns.Package.Ecosystem, pkgVulns.Package.Name, pkgVulns.Package.Version) + switch len(pkgVulns.Vulnerabilities) { + case 1: + r.Infof("1 vulnerability for the package %s has been filtered out because: %s\n", pkgString, ignoreLine.Reason) + default: + r.Infof("%d vulnerabilities for the package %s have been filtered out because: %s\n", len(pkgVulns.Vulnerabilities), pkgString, ignoreLine.Reason) + } + pkgVulns.Groups = nil + pkgVulns.Vulnerabilities = nil + + return pkgVulns + } ignoredVulns := map[string]struct{}{} // Iterate over groups first to remove all aliases of ignored vulnerabilities. var newGroups []models.GroupInfo From e378f02d2cf78ffecda85b3fad429963518e5db6 Mon Sep 17 00:00:00 2001 From: Josie Anugerah Date: Fri, 26 Apr 2024 18:13:09 +1000 Subject: [PATCH 2/7] implement overriding licenses through the config --- fixtures/testdatainner/osv-scanner.toml | 7 + pkg/config/config.go | 57 +++- pkg/config/config_internal_test.go | 247 ++++++++++++++++++ pkg/osvscanner/osvscanner.go | 2 +- pkg/osvscanner/vulnerability_result.go | 39 ++- .../vulnerability_result_internal_test.go | 120 ++++++++- 6 files changed, 442 insertions(+), 30 deletions(-) diff --git a/fixtures/testdatainner/osv-scanner.toml b/fixtures/testdatainner/osv-scanner.toml index d15175861a..ca3e52d6a5 100644 --- a/fixtures/testdatainner/osv-scanner.toml +++ b/fixtures/testdatainner/osv-scanner.toml @@ -14,3 +14,10 @@ version = "1.0.0" ecosystem = "Go" # ignore_until = 2022-11-09 # Optional exception expiry date reason = "abc" + +[[OverridePackageVersionLicenses]] +name = "my-pkg" +exactVersion = "1.0.0" +ecosystem = "Go" +licenseOverride = ["MIT", "0BSD"] +reason = "abc" diff --git a/pkg/config/config.go b/pkg/config/config.go index b1f766dad2..dd59e052c6 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "slices" + "strings" "time" "github.com/BurntSushi/toml" @@ -23,10 +24,11 @@ type ConfigManager struct { } type Config struct { - IgnoredVulns []IgnoreEntry `toml:"IgnoredVulns"` - IgnoredPackageVersions []IgnorePackageVersionEntry `toml:"IgnoredPackageVersions"` - LoadPath string `toml:"LoadPath"` - GoVersionOverride string `toml:"GoVersionOverride"` + IgnoredVulns []IgnoreEntry `toml:"IgnoredVulns"` + IgnoredPackageVersions []IgnorePackageVersionEntry `toml:"IgnoredPackageVersions"` + OverridePackageVersionLicenses []OverridePackageVersionLicenseEntry `toml:"OverridePackageVersionLicenses"` + LoadPath string `toml:"LoadPath"` + GoVersionOverride string `toml:"GoVersionOverride"` } type IgnoreEntry struct { @@ -36,15 +38,24 @@ type IgnoreEntry struct { } type IgnorePackageVersionEntry struct { - Name string `json:"name"` - Version string `json:"version"` // Q: If empty all versions of the package are ignored? - Ecosystem string `json:"ecosystem"` - // TODO: Commit? Should we use models.PackageInfo? Or keep this config - // decoupled from that model. I lean towards keeping it decoupled. + Name string `toml:"name"` + Version string `toml:"version"` + Ecosystem string `toml:"ecosystem"` IgnoreUntil time.Time `toml:"ignoreUntil"` Reason string `toml:"reason"` } +type OverridePackageVersionLicenseEntry struct { + Name string `toml:"name"` + Major string `toml:"major"` + Minor string `toml:"minor"` + Patch string `toml:"patch"` + ExactVersion string `toml:"exactVersion"` + Ecosystem string `toml:"ecosystem"` + LicenseOverride []string `toml:"licenseOverride"` + Reason string `toml:"reason"` +} + func (c *Config) ShouldIgnore(vulnID string) (bool, IgnoreEntry) { index := slices.IndexFunc(c.IgnoredVulns, func(elem IgnoreEntry) bool { return elem.ID == vulnID }) if index == -1 { @@ -71,6 +82,34 @@ func (c *Config) ShouldIgnorePackageVersion(name, version, ecosystem string) (bo return shouldIgnoreTimestamp(ignoredLine.IgnoreUntil), ignoredLine } +func (c *Config) ShouldOverridePackageVersionLicense(name, version, ecosystem string) (bool, OverridePackageVersionLicenseEntry) { + versionParts := strings.Split(version, ".") + index := slices.IndexFunc(c.OverridePackageVersionLicenses, func(elem OverridePackageVersionLicenseEntry) bool { + if ecosystem != elem.Ecosystem || name != elem.Name { + return false + } + if elem.ExactVersion != "" { + return elem.ExactVersion == version + } + if elem.Major != "" && (len(versionParts) < 1 || versionParts[0] != elem.Major) { + return false + } + if elem.Minor != "" && (len(versionParts) < 2 || versionParts[1] != elem.Minor) { + return false + } + if elem.Patch != "" && (len(versionParts) < 3 || versionParts[2] != elem.Patch) { + return false + } + + return true + }) + if index == -1 { + return false, OverridePackageVersionLicenseEntry{} + } + + return true, c.OverridePackageVersionLicenses[index] +} + func shouldIgnoreTimestamp(ignoreUntil time.Time) bool { if ignoreUntil.IsZero() { // If IgnoreUntil is not set, should ignore. diff --git a/pkg/config/config_internal_test.go b/pkg/config/config_internal_test.go index c266b911cb..ba6a145ed7 100644 --- a/pkg/config/config_internal_test.go +++ b/pkg/config/config_internal_test.go @@ -35,6 +35,15 @@ func TestTryLoadConfig(t *testing.T) { Reason: "abc", }, }, + OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ + { + Name: "my-pkg", + ExactVersion: "1.0.0", + Ecosystem: "Go", + Reason: "abc", + LicenseOverride: []string{"MIT", "0BSD"}, + }, + }, } testPaths := []testStruct{ { @@ -315,3 +324,241 @@ func TestConfig_ShouldIgnorePackageVersion(t *testing.T) { }) } } + +func TestConfig_ShouldOverridePackageVersionLicense(t *testing.T) { + t.Parallel() + + type args struct { + name string + version string + ecosystem string + } + tests := []struct { + name string + config Config + args args + wantOk bool + wantEntry OverridePackageVersionLicenseEntry + }{ + { + name: "Exact version entry exists", + config: Config{ + OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ + { + Name: "lib1", + ExactVersion: "1.0.0", + Ecosystem: "Go", + LicenseOverride: []string{"mit"}, + Reason: "abc", + }, + }, + }, + args: args{ + name: "lib1", + version: "1.0.0", + ecosystem: "Go", + }, + wantOk: true, + wantEntry: OverridePackageVersionLicenseEntry{ + Name: "lib1", + ExactVersion: "1.0.0", + Ecosystem: "Go", + LicenseOverride: []string{"mit"}, + Reason: "abc", + }, + }, + { + name: "Exact version entry doesn't exist", + config: Config{ + OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ + { + Name: "lib1", + ExactVersion: "1.0.0", + Ecosystem: "Go", + LicenseOverride: []string{"mit"}, + Reason: "abc", + }, + }, + }, + args: args{ + name: "lib1", + version: "1.0.1", + ecosystem: "Go", + }, + wantOk: false, + wantEntry: OverridePackageVersionLicenseEntry{}, + }, + { + name: "Major version matches", + config: Config{ + OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ + { + Name: "lib1", + Major: "1", + Ecosystem: "Go", + LicenseOverride: []string{"mit"}, + Reason: "abc", + }, + }, + }, + args: args{ + name: "lib1", + version: "1.0.1", + ecosystem: "Go", + }, + wantOk: true, + wantEntry: OverridePackageVersionLicenseEntry{ + Name: "lib1", + Major: "1", + Ecosystem: "Go", + LicenseOverride: []string{"mit"}, + Reason: "abc", + }, + }, + { + name: "Major and minor version matches", + config: Config{ + OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ + { + Name: "lib1", + Major: "1", + Minor: "0", + Ecosystem: "Go", + LicenseOverride: []string{"mit"}, + Reason: "abc", + }, + }, + }, + args: args{ + name: "lib1", + version: "1.0.1", + ecosystem: "Go", + }, + wantOk: true, + wantEntry: OverridePackageVersionLicenseEntry{ + Name: "lib1", + Major: "1", + Minor: "0", + Ecosystem: "Go", + LicenseOverride: []string{"mit"}, + Reason: "abc", + }, + }, + { + name: "Major, minor and patch version matches", + config: Config{ + OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ + { + Name: "lib1", + Major: "1", + Minor: "0", + Patch: "1", + Ecosystem: "Go", + LicenseOverride: []string{"mit"}, + Reason: "abc", + }, + }, + }, + args: args{ + name: "lib1", + version: "1.0.1", + ecosystem: "Go", + }, + wantOk: true, + wantEntry: OverridePackageVersionLicenseEntry{ + Name: "lib1", + Major: "1", + Minor: "0", + Patch: "1", + Ecosystem: "Go", + LicenseOverride: []string{"mit"}, + Reason: "abc", + }, + }, + { + name: "Major matches, minor doesn't", + config: Config{ + OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ + { + Name: "lib1", + Major: "1", + Minor: "2", + Ecosystem: "Go", + LicenseOverride: []string{"mit"}, + Reason: "abc", + }, + }, + }, + args: args{ + name: "lib1", + version: "1.0.1", + ecosystem: "Go", + }, + wantOk: false, + wantEntry: OverridePackageVersionLicenseEntry{}, + }, + { + name: "Major and minor matches, patch doesn't", + config: Config{ + OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ + { + Name: "lib1", + Major: "1", + Minor: "0", + Patch: "3", + Ecosystem: "Go", + LicenseOverride: []string{"mit"}, + Reason: "abc", + }, + }, + }, + args: args{ + name: "lib1", + version: "1.0.1", + ecosystem: "Go", + }, + wantOk: false, + wantEntry: OverridePackageVersionLicenseEntry{}, + }, + { + name: "Name matches", + config: Config{ + OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ + { + Name: "lib1", + Ecosystem: "Go", + LicenseOverride: []string{"mit"}, + Reason: "abc", + }, + }, + }, + args: args{ + name: "lib1", + version: "1.0.1", + ecosystem: "Go", + }, + wantOk: true, + wantEntry: OverridePackageVersionLicenseEntry{ + Name: "lib1", + Ecosystem: "Go", + LicenseOverride: []string{"mit"}, + Reason: "abc", + }, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + gotOk, gotEntry := tt.config.ShouldOverridePackageVersionLicense(tt.args.name, tt.args.version, tt.args.ecosystem) + if gotOk != tt.wantOk { + t.Errorf("ShouldOverridePackageVersionLicense() gotOk = %v, wantOk %v", gotOk, tt.wantOk) + } + if !reflect.DeepEqual(gotEntry, tt.wantEntry) { + t.Errorf("ShouldOverridePackageVersionLicense() gotEntry = %v, wantEntry %v", gotEntry, tt.wantEntry) + } + }) + } +} diff --git a/pkg/osvscanner/osvscanner.go b/pkg/osvscanner/osvscanner.go index 172ec89582..f84adda710 100644 --- a/pkg/osvscanner/osvscanner.go +++ b/pkg/osvscanner/osvscanner.go @@ -830,7 +830,7 @@ func DoScan(actions ScannerActions, r reporter.Reporter) (models.VulnerabilityRe return models.VulnerabilityResults{}, err } } - results := buildVulnerabilityResults(r, filteredScannedPackages, vulnsResp, licensesResp, actions) + results := buildVulnerabilityResults(r, filteredScannedPackages, vulnsResp, licensesResp, actions, &configManager) filtered := filterResults(r, &results, &configManager, actions.ShowAllPackages) if filtered > 0 { diff --git a/pkg/osvscanner/vulnerability_result.go b/pkg/osvscanner/vulnerability_result.go index 7657dbc4c3..cbefa932cc 100644 --- a/pkg/osvscanner/vulnerability_result.go +++ b/pkg/osvscanner/vulnerability_result.go @@ -1,11 +1,13 @@ package osvscanner import ( + "slices" "sort" "strings" "github.com/google/osv-scanner/internal/output" "github.com/google/osv-scanner/internal/sourceanalysis" + "github.com/google/osv-scanner/pkg/config" "github.com/google/osv-scanner/pkg/grouper" "github.com/google/osv-scanner/pkg/models" "github.com/google/osv-scanner/pkg/osv" @@ -22,6 +24,7 @@ func buildVulnerabilityResults( vulnsResp *osv.HydratedBatchedResponse, licensesResp [][]models.License, actions ScannerActions, + configManager *config.ConfigManager, ) models.VulnerabilityResults { results := models.VulnerabilityResults{ Results: []models.PackageSource{}, @@ -62,24 +65,34 @@ func buildVulnerabilityResults( pkg.Groups[i].MaxSeverity = output.MaxSeverity(group, pkg) } } - if len(actions.ScanLicensesAllowlist) > 0 { - pkg.Licenses = licensesResp[i] - allowlist := make(map[string]bool) - for _, license := range actions.ScanLicensesAllowlist { - allowlist[strings.ToLower(license)] = true + if actions.ScanLicensesSummary || len(actions.ScanLicensesAllowlist) > 0 { + configToUse := configManager.Get(r, rawPkg.Source.Path) + if override, entry := configToUse.ShouldOverridePackageVersionLicense(pkg.Package.Name, pkg.Package.Version, pkg.Package.Ecosystem); override { + overrideLicenses := make([]models.License, len(entry.LicenseOverride)) + for j, license := range entry.LicenseOverride { + overrideLicenses[j] = models.License(license) + } + r.Infof("overriding license for package %s/%s/%s with %s\n", pkg.Package.Ecosystem, pkg.Package.Name, pkg.Package.Version, strings.Join(entry.LicenseOverride, ",")) + licensesResp[i] = overrideLicenses } - for _, license := range pkg.Licenses { - if !allowlist[strings.ToLower(string(license))] { - pkg.LicenseViolations = append(pkg.LicenseViolations, license) + if len(actions.ScanLicensesAllowlist) > 0 { + pkg.Licenses = licensesResp[i] + for _, license := range pkg.Licenses { + lowerLicense := strings.ToLower(string(license)) + if !slices.ContainsFunc(actions.ScanLicensesAllowlist, func(l string) bool { + return strings.ToLower(l) == lowerLicense + }) { + pkg.LicenseViolations = append(pkg.LicenseViolations, license) + } + } + if len(pkg.LicenseViolations) > 0 { + includePackage = true } } - if len(pkg.LicenseViolations) > 0 { - includePackage = true + if actions.ScanLicensesSummary { + pkg.Licenses = licensesResp[i] } } - if actions.ScanLicensesSummary { - pkg.Licenses = licensesResp[i] - } if includePackage { groupedBySource[rawPkg.Source] = append(groupedBySource[rawPkg.Source], pkg) } diff --git a/pkg/osvscanner/vulnerability_result_internal_test.go b/pkg/osvscanner/vulnerability_result_internal_test.go index 5781f4ee2e..70d7d55b4a 100644 --- a/pkg/osvscanner/vulnerability_result_internal_test.go +++ b/pkg/osvscanner/vulnerability_result_internal_test.go @@ -4,6 +4,7 @@ import ( "reflect" "testing" + "github.com/google/osv-scanner/pkg/config" "github.com/google/osv-scanner/pkg/lockfile" "github.com/google/osv-scanner/pkg/models" "github.com/google/osv-scanner/pkg/osv" @@ -18,6 +19,7 @@ func Test_assembleResult(t *testing.T) { vulnsResp *osv.HydratedBatchedResponse licensesResp [][]models.License actions ScannerActions + config *config.ConfigManager } packages := []scannedPackage{ { @@ -71,6 +73,12 @@ func Test_assembleResult(t *testing.T) { {models.License("MIT")}, {models.License("UNKNOWN")}, } + makeLicensesResp := func() [][]models.License { + cpy := make([][]models.License, len(licensesResp)) + copy(cpy, licensesResp) + + return cpy + } callAnalysisStates := make(map[string]bool) @@ -84,7 +92,7 @@ func Test_assembleResult(t *testing.T) { r: &reporter.VoidReporter{}, packages: packages, vulnsResp: vulnsResp, - licensesResp: licensesResp, + licensesResp: makeLicensesResp(), actions: ScannerActions{ ExperimentalScannerActions: ExperimentalScannerActions{ ShowAllPackages: false, @@ -92,6 +100,7 @@ func Test_assembleResult(t *testing.T) { }, CallAnalysisStates: callAnalysisStates, }, + config: &config.ConfigManager{}, }, want: models.VulnerabilityResults{ Results: []models.PackageSource{ @@ -157,7 +166,7 @@ func Test_assembleResult(t *testing.T) { r: &reporter.VoidReporter{}, packages: packages, vulnsResp: vulnsResp, - licensesResp: licensesResp, + licensesResp: makeLicensesResp(), actions: ScannerActions{ ExperimentalScannerActions: ExperimentalScannerActions{ ShowAllPackages: true, @@ -165,6 +174,7 @@ func Test_assembleResult(t *testing.T) { }, CallAnalysisStates: callAnalysisStates, }, + config: &config.ConfigManager{}, }, want: models.VulnerabilityResults{ Results: []models.PackageSource{ @@ -236,7 +246,7 @@ func Test_assembleResult(t *testing.T) { r: &reporter.VoidReporter{}, packages: packages, vulnsResp: vulnsResp, - licensesResp: licensesResp, + licensesResp: makeLicensesResp(), actions: ScannerActions{ ExperimentalScannerActions: ExperimentalScannerActions{ ShowAllPackages: true, @@ -245,6 +255,7 @@ func Test_assembleResult(t *testing.T) { }, CallAnalysisStates: callAnalysisStates, }, + config: &config.ConfigManager{}, }, want: models.VulnerabilityResults{ ExperimentalAnalysisConfig: models.ExperimentalAnalysisConfig{ @@ -325,7 +336,7 @@ func Test_assembleResult(t *testing.T) { r: &reporter.VoidReporter{}, packages: packages, vulnsResp: vulnsResp, - licensesResp: licensesResp, + licensesResp: makeLicensesResp(), actions: ScannerActions{ ExperimentalScannerActions: ExperimentalScannerActions{ ShowAllPackages: false, @@ -333,6 +344,8 @@ func Test_assembleResult(t *testing.T) { }, CallAnalysisStates: callAnalysisStates, }, + + config: &config.ConfigManager{}, }, want: models.VulnerabilityResults{ ExperimentalAnalysisConfig: models.ExperimentalAnalysisConfig{ @@ -400,13 +413,105 @@ func Test_assembleResult(t *testing.T) { }, }, }, + }, { + name: "group vulnerabilities with license allowlist and license override", + args: args{ + r: &reporter.VoidReporter{}, + packages: packages, + vulnsResp: vulnsResp, + licensesResp: makeLicensesResp(), + actions: ScannerActions{ + ExperimentalScannerActions: ExperimentalScannerActions{ + ShowAllPackages: false, + ScanLicensesAllowlist: []string{"MIT", "0BSD"}, + }, + CallAnalysisStates: callAnalysisStates, + }, + config: &config.ConfigManager{ + OverrideConfig: &config.Config{ + OverridePackageVersionLicenses: []config.OverridePackageVersionLicenseEntry{ + { + Name: "pkg-3", + Ecosystem: "npm", + Major: "1", + LicenseOverride: []string{"MIT"}, + }, + }, + }, + }, + }, + want: models.VulnerabilityResults{ + ExperimentalAnalysisConfig: models.ExperimentalAnalysisConfig{ + Licenses: models.ExperimentalLicenseConfig{ + Allowlist: []models.License{models.License("MIT"), models.License("0BSD")}, + }, + }, + Results: []models.PackageSource{ + { + Source: models.SourceInfo{ + Path: "dir/package-lock.json", + Type: "lockfile", + }, + Packages: []models.PackageVulns{ + { + Package: models.PackageInfo{ + Name: "pkg-1", + Ecosystem: "npm", + Version: "1.0.0", + }, + Vulnerabilities: []models.Vulnerability{ + { + ID: "GHSA-123", + Aliases: []string{"CVE-123"}, + }, + { + ID: "CVE-123", + }, + }, + Groups: []models.GroupInfo{ + { + IDs: []string{"CVE-123", "GHSA-123"}, + Aliases: []string{"CVE-123", "GHSA-123"}, + }, + }, + Licenses: makeLicenses([]string{"MIT", "0BSD"}), + }, + }, + }, + { + Source: models.SourceInfo{ + Path: "other-dir/package-lock.json", + Type: "lockfile", + }, + Packages: []models.PackageVulns{ + { + Package: models.PackageInfo{ + Name: "pkg-3", + Ecosystem: "npm", + Version: "1.0.0", + }, + Vulnerabilities: []models.Vulnerability{ + {ID: "GHSA-456"}, + }, + Groups: []models.GroupInfo{ + { + IDs: []string{"GHSA-456"}, + Aliases: []string{"GHSA-456"}, + }, + }, + Licenses: makeLicenses([]string{"MIT"}), + }, + }, + }, + }, + }, }, { name: "group vulnerabilities, with license allowlist and all packages", args: args{ r: &reporter.VoidReporter{}, packages: packages, vulnsResp: vulnsResp, - licensesResp: licensesResp, + licensesResp: makeLicensesResp(), actions: ScannerActions{ ExperimentalScannerActions: ExperimentalScannerActions{ ShowAllPackages: true, @@ -414,6 +519,7 @@ func Test_assembleResult(t *testing.T) { }, CallAnalysisStates: callAnalysisStates, }, + config: &config.ConfigManager{}, }, want: models.VulnerabilityResults{ ExperimentalAnalysisConfig: models.ExperimentalAnalysisConfig{ @@ -493,8 +599,8 @@ func Test_assembleResult(t *testing.T) { tt := tt // Reinitialize for t.Parallel() t.Run(tt.name, func(t *testing.T) { t.Parallel() - if got := buildVulnerabilityResults(tt.args.r, tt.args.packages, tt.args.vulnsResp, tt.args.licensesResp, tt.args.actions); !reflect.DeepEqual(got, tt.want) { - t.Errorf("buildVulnerabilityResults() = %v,\nwant %v", got, tt.want) + if got := buildVulnerabilityResults(tt.args.r, tt.args.packages, tt.args.vulnsResp, tt.args.licensesResp, tt.args.actions, tt.args.config); !reflect.DeepEqual(got, tt.want) { + t.Errorf("buildVulnerabilityResults() = %+v,\nwant %+v", got, tt.want) } }) } From acd5c2357e146b6607ef505902aa566ede270b4c Mon Sep 17 00:00:00 2001 From: Josie Anugerah Date: Tue, 7 May 2024 10:29:57 +1000 Subject: [PATCH 3/7] respond to comments --- pkg/config/config.go | 84 +-- .../vulnerability_result_internal_test.snap | 586 ++++++++++++++++++ pkg/osvscanner/vulnerability_result.go | 6 +- .../vulnerability_result_internal_test.go | 428 +------------ 4 files changed, 634 insertions(+), 470 deletions(-) create mode 100755 pkg/osvscanner/__snapshots__/vulnerability_result_internal_test.snap diff --git a/pkg/config/config.go b/pkg/config/config.go index dd59e052c6..81c37e1916 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -5,7 +5,6 @@ import ( "os" "path/filepath" "slices" - "strings" "time" "github.com/BurntSushi/toml" @@ -24,11 +23,10 @@ type ConfigManager struct { } type Config struct { - IgnoredVulns []IgnoreEntry `toml:"IgnoredVulns"` - IgnoredPackageVersions []IgnorePackageVersionEntry `toml:"IgnoredPackageVersions"` - OverridePackageVersionLicenses []OverridePackageVersionLicenseEntry `toml:"OverridePackageVersionLicenses"` - LoadPath string `toml:"LoadPath"` - GoVersionOverride string `toml:"GoVersionOverride"` + IgnoredVulns []IgnoreEntry `toml:"IgnoredVulns"` + PackageVersions []PackageVersionEntry `toml:"PackageVersionEntry"` + LoadPath string `toml:"LoadPath"` + GoVersionOverride string `toml:"GoVersionOverride"` } type IgnoreEntry struct { @@ -37,27 +35,23 @@ type IgnoreEntry struct { Reason string `toml:"reason"` } -type IgnorePackageVersionEntry struct { - Name string `toml:"name"` - Version string `toml:"version"` - Ecosystem string `toml:"ecosystem"` - IgnoreUntil time.Time `toml:"ignoreUntil"` - Reason string `toml:"reason"` +type PackageVersionEntry struct { + Name string `toml:"name"` + // If the version is empty, the entry applies to all versions. + Version string `toml:"version"` + Ecosystem string `toml:"ecosystem"` + Ignore bool `toml:"ignore"` + License License `toml:"license"` + EffectiveUntil time.Time `toml:"ignoreUntil"` + Reason string `toml:"reason"` } -type OverridePackageVersionLicenseEntry struct { - Name string `toml:"name"` - Major string `toml:"major"` - Minor string `toml:"minor"` - Patch string `toml:"patch"` - ExactVersion string `toml:"exactVersion"` - Ecosystem string `toml:"ecosystem"` - LicenseOverride []string `toml:"licenseOverride"` - Reason string `toml:"reason"` +type License struct { + Override []string `toml:"override"` } func (c *Config) ShouldIgnore(vulnID string) (bool, IgnoreEntry) { - index := slices.IndexFunc(c.IgnoredVulns, func(elem IgnoreEntry) bool { return elem.ID == vulnID }) + index := slices.IndexFunc(c.IgnoredVulns, func(e IgnoreEntry) bool { return e.ID == vulnID }) if index == -1 { return false, IgnoreEntry{} } @@ -66,48 +60,32 @@ func (c *Config) ShouldIgnore(vulnID string) (bool, IgnoreEntry) { return shouldIgnoreTimestamp(ignoredLine.IgnoreUntil), ignoredLine } -func (c *Config) ShouldIgnorePackageVersion(name, version, ecosystem string) (bool, IgnorePackageVersionEntry) { - index := slices.IndexFunc(c.IgnoredPackageVersions, func(elem IgnorePackageVersionEntry) bool { - if name != elem.Name { +func (c *Config) filterPackageVersionEntries(name string, version string, ecosystem string, condition func(PackageVersionEntry) bool) (bool, PackageVersionEntry) { + index := slices.IndexFunc(c.PackageVersions, func(e PackageVersionEntry) bool { + if name != e.Name { return false } - return version == elem.Version || elem.Version == "" + return (version == e.Version || e.Version == "") && condition(e) }) if index == -1 { - return false, IgnorePackageVersionEntry{} + return false, PackageVersionEntry{} } - ignoredLine := c.IgnoredPackageVersions[index] + ignoredLine := c.PackageVersions[index] - return shouldIgnoreTimestamp(ignoredLine.IgnoreUntil), ignoredLine + return shouldIgnoreTimestamp(ignoredLine.EffectiveUntil), ignoredLine } -func (c *Config) ShouldOverridePackageVersionLicense(name, version, ecosystem string) (bool, OverridePackageVersionLicenseEntry) { - versionParts := strings.Split(version, ".") - index := slices.IndexFunc(c.OverridePackageVersionLicenses, func(elem OverridePackageVersionLicenseEntry) bool { - if ecosystem != elem.Ecosystem || name != elem.Name { - return false - } - if elem.ExactVersion != "" { - return elem.ExactVersion == version - } - if elem.Major != "" && (len(versionParts) < 1 || versionParts[0] != elem.Major) { - return false - } - if elem.Minor != "" && (len(versionParts) < 2 || versionParts[1] != elem.Minor) { - return false - } - if elem.Patch != "" && (len(versionParts) < 3 || versionParts[2] != elem.Patch) { - return false - } - - return true +func (c *Config) ShouldIgnorePackageVersion(name, version, ecosystem string) (bool, PackageVersionEntry) { + return c.filterPackageVersionEntries(name, version, ecosystem, func(e PackageVersionEntry) bool { + return e.Ignore }) - if index == -1 { - return false, OverridePackageVersionLicenseEntry{} - } +} - return true, c.OverridePackageVersionLicenses[index] +func (c *Config) ShouldOverridePackageVersionLicense(name, version, ecosystem string) (bool, PackageVersionEntry) { + return c.filterPackageVersionEntries(name, version, ecosystem, func(e PackageVersionEntry) bool { + return len(e.License.Override) > 0 + }) } func shouldIgnoreTimestamp(ignoreUntil time.Time) bool { diff --git a/pkg/osvscanner/__snapshots__/vulnerability_result_internal_test.snap b/pkg/osvscanner/__snapshots__/vulnerability_result_internal_test.snap new file mode 100755 index 0000000000..c13d95b957 --- /dev/null +++ b/pkg/osvscanner/__snapshots__/vulnerability_result_internal_test.snap @@ -0,0 +1,586 @@ + +[Test_assembleResult/group_vulnerabilities - 1] +{ + "results": [ + { + "source": { + "path": "dir/package-lock.json", + "type": "lockfile" + }, + "packages": [ + { + "package": { + "name": "pkg-1", + "version": "1.0.0", + "ecosystem": "npm" + }, + "vulnerabilities": [ + { + "modified": "0001-01-01T00:00:00Z", + "id": "GHSA-123", + "aliases": [ + "CVE-123" + ] + }, + { + "modified": "0001-01-01T00:00:00Z", + "id": "CVE-123" + } + ], + "groups": [ + { + "ids": [ + "CVE-123", + "GHSA-123" + ], + "aliases": [ + "CVE-123", + "GHSA-123" + ], + "max_severity": "" + } + ] + } + ] + }, + { + "source": { + "path": "other-dir/package-lock.json", + "type": "lockfile" + }, + "packages": [ + { + "package": { + "name": "pkg-3", + "version": "1.0.0", + "ecosystem": "npm" + }, + "vulnerabilities": [ + { + "modified": "0001-01-01T00:00:00Z", + "id": "GHSA-456" + } + ], + "groups": [ + { + "ids": [ + "GHSA-456" + ], + "aliases": [ + "GHSA-456" + ], + "max_severity": "" + } + ] + } + ] + } + ], + "experimental_config": { + "licenses": { + "summary": false, + "allowlist": null + } + } +} +--- + +[Test_assembleResult/group_vulnerabilities,_with_license_allowlist_and_all_packages - 1] +{ + "results": [ + { + "source": { + "path": "dir/package-lock.json", + "type": "lockfile" + }, + "packages": [ + { + "package": { + "name": "pkg-1", + "version": "1.0.0", + "ecosystem": "npm" + }, + "vulnerabilities": [ + { + "modified": "0001-01-01T00:00:00Z", + "id": "GHSA-123", + "aliases": [ + "CVE-123" + ] + }, + { + "modified": "0001-01-01T00:00:00Z", + "id": "CVE-123" + } + ], + "groups": [ + { + "ids": [ + "CVE-123", + "GHSA-123" + ], + "aliases": [ + "CVE-123", + "GHSA-123" + ], + "max_severity": "" + } + ], + "licenses": [ + "MIT", + "0BSD" + ] + }, + { + "package": { + "name": "pkg-2", + "version": "1.0.0", + "ecosystem": "npm" + }, + "licenses": [ + "MIT" + ] + } + ] + }, + { + "source": { + "path": "other-dir/package-lock.json", + "type": "lockfile" + }, + "packages": [ + { + "package": { + "name": "pkg-3", + "version": "1.0.0", + "ecosystem": "npm" + }, + "vulnerabilities": [ + { + "modified": "0001-01-01T00:00:00Z", + "id": "GHSA-456" + } + ], + "groups": [ + { + "ids": [ + "GHSA-456" + ], + "aliases": [ + "GHSA-456" + ], + "max_severity": "" + } + ], + "licenses": [ + "UNKNOWN" + ], + "license_violations": [ + "UNKNOWN" + ] + } + ] + } + ], + "experimental_config": { + "licenses": { + "summary": false, + "allowlist": [ + "MIT", + "0BSD" + ] + } + } +} +--- + +[Test_assembleResult/group_vulnerabilities_with_all_packages_included - 1] +{ + "results": [ + { + "source": { + "path": "dir/package-lock.json", + "type": "lockfile" + }, + "packages": [ + { + "package": { + "name": "pkg-1", + "version": "1.0.0", + "ecosystem": "npm" + }, + "vulnerabilities": [ + { + "modified": "0001-01-01T00:00:00Z", + "id": "GHSA-123", + "aliases": [ + "CVE-123" + ] + }, + { + "modified": "0001-01-01T00:00:00Z", + "id": "CVE-123" + } + ], + "groups": [ + { + "ids": [ + "CVE-123", + "GHSA-123" + ], + "aliases": [ + "CVE-123", + "GHSA-123" + ], + "max_severity": "" + } + ] + }, + { + "package": { + "name": "pkg-2", + "version": "1.0.0", + "ecosystem": "npm" + } + } + ] + }, + { + "source": { + "path": "other-dir/package-lock.json", + "type": "lockfile" + }, + "packages": [ + { + "package": { + "name": "pkg-3", + "version": "1.0.0", + "ecosystem": "npm" + }, + "vulnerabilities": [ + { + "modified": "0001-01-01T00:00:00Z", + "id": "GHSA-456" + } + ], + "groups": [ + { + "ids": [ + "GHSA-456" + ], + "aliases": [ + "GHSA-456" + ], + "max_severity": "" + } + ] + } + ] + } + ], + "experimental_config": { + "licenses": { + "summary": false, + "allowlist": null + } + } +} +--- + +[Test_assembleResult/group_vulnerabilities_with_license_allowlist - 1] +{ + "results": [ + { + "source": { + "path": "dir/package-lock.json", + "type": "lockfile" + }, + "packages": [ + { + "package": { + "name": "pkg-1", + "version": "1.0.0", + "ecosystem": "npm" + }, + "vulnerabilities": [ + { + "modified": "0001-01-01T00:00:00Z", + "id": "GHSA-123", + "aliases": [ + "CVE-123" + ] + }, + { + "modified": "0001-01-01T00:00:00Z", + "id": "CVE-123" + } + ], + "groups": [ + { + "ids": [ + "CVE-123", + "GHSA-123" + ], + "aliases": [ + "CVE-123", + "GHSA-123" + ], + "max_severity": "" + } + ], + "licenses": [ + "MIT", + "0BSD" + ] + } + ] + }, + { + "source": { + "path": "other-dir/package-lock.json", + "type": "lockfile" + }, + "packages": [ + { + "package": { + "name": "pkg-3", + "version": "1.0.0", + "ecosystem": "npm" + }, + "vulnerabilities": [ + { + "modified": "0001-01-01T00:00:00Z", + "id": "GHSA-456" + } + ], + "groups": [ + { + "ids": [ + "GHSA-456" + ], + "aliases": [ + "GHSA-456" + ], + "max_severity": "" + } + ], + "licenses": [ + "UNKNOWN" + ], + "license_violations": [ + "UNKNOWN" + ] + } + ] + } + ], + "experimental_config": { + "licenses": { + "summary": false, + "allowlist": [ + "MIT", + "0BSD" + ] + } + } +} +--- + +[Test_assembleResult/group_vulnerabilities_with_license_allowlist_and_license_override - 1] +{ + "results": [ + { + "source": { + "path": "dir/package-lock.json", + "type": "lockfile" + }, + "packages": [ + { + "package": { + "name": "pkg-1", + "version": "1.0.0", + "ecosystem": "npm" + }, + "vulnerabilities": [ + { + "modified": "0001-01-01T00:00:00Z", + "id": "GHSA-123", + "aliases": [ + "CVE-123" + ] + }, + { + "modified": "0001-01-01T00:00:00Z", + "id": "CVE-123" + } + ], + "groups": [ + { + "ids": [ + "CVE-123", + "GHSA-123" + ], + "aliases": [ + "CVE-123", + "GHSA-123" + ], + "max_severity": "" + } + ], + "licenses": [ + "MIT", + "0BSD" + ] + } + ] + }, + { + "source": { + "path": "other-dir/package-lock.json", + "type": "lockfile" + }, + "packages": [ + { + "package": { + "name": "pkg-3", + "version": "1.0.0", + "ecosystem": "npm" + }, + "vulnerabilities": [ + { + "modified": "0001-01-01T00:00:00Z", + "id": "GHSA-456" + } + ], + "groups": [ + { + "ids": [ + "GHSA-456" + ], + "aliases": [ + "GHSA-456" + ], + "max_severity": "" + } + ], + "licenses": [ + "MIT" + ] + } + ] + } + ], + "experimental_config": { + "licenses": { + "summary": false, + "allowlist": [ + "MIT", + "0BSD" + ] + } + } +} +--- + +[Test_assembleResult/group_vulnerabilities_with_licenses - 1] +{ + "results": [ + { + "source": { + "path": "dir/package-lock.json", + "type": "lockfile" + }, + "packages": [ + { + "package": { + "name": "pkg-1", + "version": "1.0.0", + "ecosystem": "npm" + }, + "vulnerabilities": [ + { + "modified": "0001-01-01T00:00:00Z", + "id": "GHSA-123", + "aliases": [ + "CVE-123" + ] + }, + { + "modified": "0001-01-01T00:00:00Z", + "id": "CVE-123" + } + ], + "groups": [ + { + "ids": [ + "CVE-123", + "GHSA-123" + ], + "aliases": [ + "CVE-123", + "GHSA-123" + ], + "max_severity": "" + } + ], + "licenses": [ + "MIT", + "0BSD" + ] + }, + { + "package": { + "name": "pkg-2", + "version": "1.0.0", + "ecosystem": "npm" + }, + "licenses": [ + "MIT" + ] + } + ] + }, + { + "source": { + "path": "other-dir/package-lock.json", + "type": "lockfile" + }, + "packages": [ + { + "package": { + "name": "pkg-3", + "version": "1.0.0", + "ecosystem": "npm" + }, + "vulnerabilities": [ + { + "modified": "0001-01-01T00:00:00Z", + "id": "GHSA-456" + } + ], + "groups": [ + { + "ids": [ + "GHSA-456" + ], + "aliases": [ + "GHSA-456" + ], + "max_severity": "" + } + ], + "licenses": [ + "UNKNOWN" + ] + } + ] + } + ], + "experimental_config": { + "licenses": { + "summary": true, + "allowlist": [] + } + } +} +--- diff --git a/pkg/osvscanner/vulnerability_result.go b/pkg/osvscanner/vulnerability_result.go index cbefa932cc..88cf7d02fe 100644 --- a/pkg/osvscanner/vulnerability_result.go +++ b/pkg/osvscanner/vulnerability_result.go @@ -68,11 +68,11 @@ func buildVulnerabilityResults( if actions.ScanLicensesSummary || len(actions.ScanLicensesAllowlist) > 0 { configToUse := configManager.Get(r, rawPkg.Source.Path) if override, entry := configToUse.ShouldOverridePackageVersionLicense(pkg.Package.Name, pkg.Package.Version, pkg.Package.Ecosystem); override { - overrideLicenses := make([]models.License, len(entry.LicenseOverride)) - for j, license := range entry.LicenseOverride { + overrideLicenses := make([]models.License, len(entry.License.Override)) + for j, license := range entry.License.Override { overrideLicenses[j] = models.License(license) } - r.Infof("overriding license for package %s/%s/%s with %s\n", pkg.Package.Ecosystem, pkg.Package.Name, pkg.Package.Version, strings.Join(entry.LicenseOverride, ",")) + r.Infof("overriding license for package %s/%s/%s with %s\n", pkg.Package.Ecosystem, pkg.Package.Name, pkg.Package.Version, strings.Join(entry.License.Override, ",")) licensesResp[i] = overrideLicenses } if len(actions.ScanLicensesAllowlist) > 0 { diff --git a/pkg/osvscanner/vulnerability_result_internal_test.go b/pkg/osvscanner/vulnerability_result_internal_test.go index 70d7d55b4a..f3453cfeb8 100644 --- a/pkg/osvscanner/vulnerability_result_internal_test.go +++ b/pkg/osvscanner/vulnerability_result_internal_test.go @@ -1,9 +1,9 @@ package osvscanner import ( - "reflect" "testing" + "github.com/google/osv-scanner/internal/testutility" "github.com/google/osv-scanner/pkg/config" "github.com/google/osv-scanner/pkg/lockfile" "github.com/google/osv-scanner/pkg/models" @@ -85,9 +85,8 @@ func Test_assembleResult(t *testing.T) { tests := []struct { name string args args - want models.VulnerabilityResults }{{ - name: "group vulnerabilities", + name: "group_vulnerabilities", args: args{ r: &reporter.VoidReporter{}, packages: packages, @@ -102,66 +101,8 @@ func Test_assembleResult(t *testing.T) { }, config: &config.ConfigManager{}, }, - want: models.VulnerabilityResults{ - Results: []models.PackageSource{ - { - Source: models.SourceInfo{ - Path: "dir/package-lock.json", - Type: "lockfile", - }, - Packages: []models.PackageVulns{ - { - Package: models.PackageInfo{ - Name: "pkg-1", - Ecosystem: "npm", - Version: "1.0.0", - }, - Vulnerabilities: []models.Vulnerability{ - { - ID: "GHSA-123", - Aliases: []string{"CVE-123"}, - }, - { - ID: "CVE-123", - }, - }, - Groups: []models.GroupInfo{ - { - IDs: []string{"CVE-123", "GHSA-123"}, - Aliases: []string{"CVE-123", "GHSA-123"}, - }, - }, - }, - }, - }, - { - Source: models.SourceInfo{ - Path: "other-dir/package-lock.json", - Type: "lockfile", - }, - Packages: []models.PackageVulns{ - { - Package: models.PackageInfo{ - Name: "pkg-3", - Ecosystem: "npm", - Version: "1.0.0", - }, - Vulnerabilities: []models.Vulnerability{ - {ID: "GHSA-456"}, - }, - Groups: []models.GroupInfo{ - { - IDs: []string{"GHSA-456"}, - Aliases: []string{"GHSA-456"}, - }, - }, - }, - }, - }, - }, - }, }, { - name: "group vulnerabilities, with all packages included", + name: "group_vulnerabilities_with_all_packages_included", args: args{ r: &reporter.VoidReporter{}, packages: packages, @@ -176,72 +117,8 @@ func Test_assembleResult(t *testing.T) { }, config: &config.ConfigManager{}, }, - want: models.VulnerabilityResults{ - Results: []models.PackageSource{ - { - Source: models.SourceInfo{ - Path: "dir/package-lock.json", - Type: "lockfile", - }, - Packages: []models.PackageVulns{ - { - Package: models.PackageInfo{ - Name: "pkg-1", - Ecosystem: "npm", - Version: "1.0.0", - }, - Vulnerabilities: []models.Vulnerability{ - { - ID: "GHSA-123", - Aliases: []string{"CVE-123"}, - }, - { - ID: "CVE-123", - }, - }, - Groups: []models.GroupInfo{ - { - IDs: []string{"CVE-123", "GHSA-123"}, - Aliases: []string{"CVE-123", "GHSA-123"}, - }, - }, - }, { - Package: models.PackageInfo{ - Name: "pkg-2", - Ecosystem: "npm", - Version: "1.0.0", - }, - }, - }, - }, - { - Source: models.SourceInfo{ - Path: "other-dir/package-lock.json", - Type: "lockfile", - }, - Packages: []models.PackageVulns{ - { - Package: models.PackageInfo{ - Name: "pkg-3", - Ecosystem: "npm", - Version: "1.0.0", - }, - Vulnerabilities: []models.Vulnerability{ - {ID: "GHSA-456"}, - }, - Groups: []models.GroupInfo{ - { - IDs: []string{"GHSA-456"}, - Aliases: []string{"GHSA-456"}, - }, - }, - }, - }, - }, - }, - }, }, { - name: "group vulnerabilities with licenses", + name: "group_vulnerabilities_with_licenses", args: args{ r: &reporter.VoidReporter{}, packages: packages, @@ -257,81 +134,8 @@ func Test_assembleResult(t *testing.T) { }, config: &config.ConfigManager{}, }, - want: models.VulnerabilityResults{ - ExperimentalAnalysisConfig: models.ExperimentalAnalysisConfig{ - Licenses: models.ExperimentalLicenseConfig{ - Summary: true, - Allowlist: []models.License{}, - }, - }, - Results: []models.PackageSource{ - { - Source: models.SourceInfo{ - Path: "dir/package-lock.json", - Type: "lockfile", - }, - Packages: []models.PackageVulns{ - { - Package: models.PackageInfo{ - Name: "pkg-1", - Ecosystem: "npm", - Version: "1.0.0", - }, - Vulnerabilities: []models.Vulnerability{ - { - ID: "GHSA-123", - Aliases: []string{"CVE-123"}, - }, - { - ID: "CVE-123", - }, - }, - Groups: []models.GroupInfo{ - { - IDs: []string{"CVE-123", "GHSA-123"}, - Aliases: []string{"CVE-123", "GHSA-123"}, - }, - }, - Licenses: makeLicenses([]string{"MIT", "0BSD"}), - }, { - Package: models.PackageInfo{ - Name: "pkg-2", - Ecosystem: "npm", - Version: "1.0.0", - }, - Licenses: makeLicenses([]string{"MIT"}), - }, - }, - }, - { - Source: models.SourceInfo{ - Path: "other-dir/package-lock.json", - Type: "lockfile", - }, - Packages: []models.PackageVulns{ - { - Package: models.PackageInfo{ - Name: "pkg-3", - Ecosystem: "npm", - Version: "1.0.0", - }, - Vulnerabilities: []models.Vulnerability{ - {ID: "GHSA-456"}, - }, - Groups: []models.GroupInfo{ - { - IDs: []string{"GHSA-456"}, - Aliases: []string{"GHSA-456"}, - }, - }, - Licenses: makeLicenses([]string{"UNKNOWN"}), - }, - }, - }, - }, - }, }, { - name: "group vulnerabilities with license allowlist", + name: "group_vulnerabilities_with_license_allowlist", args: args{ r: &reporter.VoidReporter{}, packages: packages, @@ -347,74 +151,8 @@ func Test_assembleResult(t *testing.T) { config: &config.ConfigManager{}, }, - want: models.VulnerabilityResults{ - ExperimentalAnalysisConfig: models.ExperimentalAnalysisConfig{ - Licenses: models.ExperimentalLicenseConfig{ - Allowlist: []models.License{models.License("MIT"), models.License("0BSD")}, - }, - }, - Results: []models.PackageSource{ - { - Source: models.SourceInfo{ - Path: "dir/package-lock.json", - Type: "lockfile", - }, - Packages: []models.PackageVulns{ - { - Package: models.PackageInfo{ - Name: "pkg-1", - Ecosystem: "npm", - Version: "1.0.0", - }, - Vulnerabilities: []models.Vulnerability{ - { - ID: "GHSA-123", - Aliases: []string{"CVE-123"}, - }, - { - ID: "CVE-123", - }, - }, - Groups: []models.GroupInfo{ - { - IDs: []string{"CVE-123", "GHSA-123"}, - Aliases: []string{"CVE-123", "GHSA-123"}, - }, - }, - Licenses: makeLicenses([]string{"MIT", "0BSD"}), - }, - }, - }, - { - Source: models.SourceInfo{ - Path: "other-dir/package-lock.json", - Type: "lockfile", - }, - Packages: []models.PackageVulns{ - { - Package: models.PackageInfo{ - Name: "pkg-3", - Ecosystem: "npm", - Version: "1.0.0", - }, - Vulnerabilities: []models.Vulnerability{ - {ID: "GHSA-456"}, - }, - Groups: []models.GroupInfo{ - { - IDs: []string{"GHSA-456"}, - Aliases: []string{"GHSA-456"}, - }, - }, - Licenses: makeLicenses([]string{"UNKNOWN"}), - LicenseViolations: makeLicenses([]string{"UNKNOWN"}), - }, - }, - }, - }, - }, }, { - name: "group vulnerabilities with license allowlist and license override", + name: "group_vulnerabilities_with_license_allowlist_and_license_override", args: args{ r: &reporter.VoidReporter{}, packages: packages, @@ -429,84 +167,20 @@ func Test_assembleResult(t *testing.T) { }, config: &config.ConfigManager{ OverrideConfig: &config.Config{ - OverridePackageVersionLicenses: []config.OverridePackageVersionLicenseEntry{ - { - Name: "pkg-3", - Ecosystem: "npm", - Major: "1", - LicenseOverride: []string{"MIT"}, - }, - }, - }, - }, - }, - want: models.VulnerabilityResults{ - ExperimentalAnalysisConfig: models.ExperimentalAnalysisConfig{ - Licenses: models.ExperimentalLicenseConfig{ - Allowlist: []models.License{models.License("MIT"), models.License("0BSD")}, - }, - }, - Results: []models.PackageSource{ - { - Source: models.SourceInfo{ - Path: "dir/package-lock.json", - Type: "lockfile", - }, - Packages: []models.PackageVulns{ + PackageVersions: []config.PackageVersionEntry{ { - Package: models.PackageInfo{ - Name: "pkg-1", - Ecosystem: "npm", - Version: "1.0.0", - }, - Vulnerabilities: []models.Vulnerability{ - { - ID: "GHSA-123", - Aliases: []string{"CVE-123"}, - }, - { - ID: "CVE-123", - }, - }, - Groups: []models.GroupInfo{ - { - IDs: []string{"CVE-123", "GHSA-123"}, - Aliases: []string{"CVE-123", "GHSA-123"}, - }, + Name: "pkg-3", + Ecosystem: "npm", + License: config.License{ + Override: []string{"MIT"}, }, - Licenses: makeLicenses([]string{"MIT", "0BSD"}), - }, - }, - }, - { - Source: models.SourceInfo{ - Path: "other-dir/package-lock.json", - Type: "lockfile", - }, - Packages: []models.PackageVulns{ - { - Package: models.PackageInfo{ - Name: "pkg-3", - Ecosystem: "npm", - Version: "1.0.0", - }, - Vulnerabilities: []models.Vulnerability{ - {ID: "GHSA-456"}, - }, - Groups: []models.GroupInfo{ - { - IDs: []string{"GHSA-456"}, - Aliases: []string{"GHSA-456"}, - }, - }, - Licenses: makeLicenses([]string{"MIT"}), }, }, }, }, }, }, { - name: "group vulnerabilities, with license allowlist and all packages", + name: "group_vulnerabilities,_with_license_allowlist_and_all_packages", args: args{ r: &reporter.VoidReporter{}, packages: packages, @@ -521,87 +195,13 @@ func Test_assembleResult(t *testing.T) { }, config: &config.ConfigManager{}, }, - want: models.VulnerabilityResults{ - ExperimentalAnalysisConfig: models.ExperimentalAnalysisConfig{ - Licenses: models.ExperimentalLicenseConfig{ - Allowlist: []models.License{models.License("MIT"), models.License("0BSD")}, - }, - }, - Results: []models.PackageSource{ - { - Source: models.SourceInfo{ - Path: "dir/package-lock.json", - Type: "lockfile", - }, - Packages: []models.PackageVulns{ - { - Package: models.PackageInfo{ - Name: "pkg-1", - Ecosystem: "npm", - Version: "1.0.0", - }, - Vulnerabilities: []models.Vulnerability{ - { - ID: "GHSA-123", - Aliases: []string{"CVE-123"}, - }, - { - ID: "CVE-123", - }, - }, - Groups: []models.GroupInfo{ - { - IDs: []string{"CVE-123", "GHSA-123"}, - Aliases: []string{"CVE-123", "GHSA-123"}, - }, - }, - Licenses: makeLicenses([]string{"MIT", "0BSD"}), - }, { - Package: models.PackageInfo{ - Name: "pkg-2", - Ecosystem: "npm", - Version: "1.0.0", - }, - Licenses: makeLicenses([]string{"MIT"}), - }, - }, - }, - { - Source: models.SourceInfo{ - Path: "other-dir/package-lock.json", - Type: "lockfile", - }, - Packages: []models.PackageVulns{ - { - Package: models.PackageInfo{ - Name: "pkg-3", - Ecosystem: "npm", - Version: "1.0.0", - }, - Vulnerabilities: []models.Vulnerability{ - {ID: "GHSA-456"}, - }, - Groups: []models.GroupInfo{ - { - IDs: []string{"GHSA-456"}, - Aliases: []string{"GHSA-456"}, - }, - }, - Licenses: makeLicenses([]string{"UNKNOWN"}), - LicenseViolations: makeLicenses([]string{"UNKNOWN"}), - }, - }, - }, - }, - }, }} for _, tt := range tests { tt := tt // Reinitialize for t.Parallel() t.Run(tt.name, func(t *testing.T) { t.Parallel() - if got := buildVulnerabilityResults(tt.args.r, tt.args.packages, tt.args.vulnsResp, tt.args.licensesResp, tt.args.actions, tt.args.config); !reflect.DeepEqual(got, tt.want) { - t.Errorf("buildVulnerabilityResults() = %+v,\nwant %+v", got, tt.want) - } + got := buildVulnerabilityResults(tt.args.r, tt.args.packages, tt.args.vulnsResp, tt.args.licensesResp, tt.args.actions, tt.args.config) + testutility.NewSnapshot().MatchJSON(t, got) }) } } From ce63db61d3c12bda411e41cbe8a5be308f0c5aad Mon Sep 17 00:00:00 2001 From: Josie Anugerah Date: Tue, 7 May 2024 10:58:45 +1000 Subject: [PATCH 4/7] linter --- fixtures/testdatainner/osv-scanner.toml | 18 +- pkg/config/config.go | 6 +- pkg/config/config_internal_test.go | 300 ++++++------------ .../vulnerability_result_internal_test.go | 11 +- 4 files changed, 107 insertions(+), 228 deletions(-) diff --git a/fixtures/testdatainner/osv-scanner.toml b/fixtures/testdatainner/osv-scanner.toml index ca3e52d6a5..52b1a667e7 100644 --- a/fixtures/testdatainner/osv-scanner.toml +++ b/fixtures/testdatainner/osv-scanner.toml @@ -1,23 +1,25 @@ [[IgnoredVulns]] id = "GO-2022-0968" -# ignore_until = 2022-11-09 +# ignoreUntil = 2022-11-09 # reason = "" # Optional reason [[IgnoredVulns]] id = "GO-2022-1059" -# ignore_until = 2022-11-09 # Optional exception expiry date +# ignoreUntil = 2022-11-09 # Optional exception expiry date # reason = "" # Optional reason -[[IgnoredPackageVersions]] +[[PackageVersions]] name = "lib" version = "1.0.0" ecosystem = "Go" -# ignore_until = 2022-11-09 # Optional exception expiry date +ignore = true +# effectiveUntil = 2022-11-09 # Optional exception expiry date reason = "abc" - -[[OverridePackageVersionLicenses]] + +[[PackageVersions]] name = "my-pkg" -exactVersion = "1.0.0" +version = "1.0.0" ecosystem = "Go" -licenseOverride = ["MIT", "0BSD"] +ignore = true reason = "abc" +license.override = ["MIT", "0BSD"] diff --git a/pkg/config/config.go b/pkg/config/config.go index 81c37e1916..814b501251 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -24,7 +24,7 @@ type ConfigManager struct { type Config struct { IgnoredVulns []IgnoreEntry `toml:"IgnoredVulns"` - PackageVersions []PackageVersionEntry `toml:"PackageVersionEntry"` + PackageVersions []PackageVersionEntry `toml:"PackageVersions"` LoadPath string `toml:"LoadPath"` GoVersionOverride string `toml:"GoVersionOverride"` } @@ -42,7 +42,7 @@ type PackageVersionEntry struct { Ecosystem string `toml:"ecosystem"` Ignore bool `toml:"ignore"` License License `toml:"license"` - EffectiveUntil time.Time `toml:"ignoreUntil"` + EffectiveUntil time.Time `toml:"effectiveUntil"` Reason string `toml:"reason"` } @@ -62,7 +62,7 @@ func (c *Config) ShouldIgnore(vulnID string) (bool, IgnoreEntry) { func (c *Config) filterPackageVersionEntries(name string, version string, ecosystem string, condition func(PackageVersionEntry) bool) (bool, PackageVersionEntry) { index := slices.IndexFunc(c.PackageVersions, func(e PackageVersionEntry) bool { - if name != e.Name { + if ecosystem != e.Ecosystem || name != e.Name { return false } diff --git a/pkg/config/config_internal_test.go b/pkg/config/config_internal_test.go index ba6a145ed7..0381042356 100644 --- a/pkg/config/config_internal_test.go +++ b/pkg/config/config_internal_test.go @@ -27,21 +27,23 @@ func TestTryLoadConfig(t *testing.T) { ID: "GO-2022-1059", }, }, - IgnoredPackageVersions: []IgnorePackageVersionEntry{ + PackageVersions: []PackageVersionEntry{ { Name: "lib", Version: "1.0.0", Ecosystem: "Go", + Ignore: true, Reason: "abc", }, - }, - OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ { - Name: "my-pkg", - ExactVersion: "1.0.0", - Ecosystem: "Go", - Reason: "abc", - LicenseOverride: []string{"MIT", "0BSD"}, + Name: "my-pkg", + Version: "1.0.0", + Ecosystem: "Go", + Reason: "abc", + Ignore: true, + License: License{ + Override: []string{"MIT", "0BSD"}, + }, }, }, } @@ -86,7 +88,7 @@ func TestTryLoadConfig(t *testing.T) { if !cmp.Equal(config.IgnoredVulns, testData.config.IgnoredVulns) { t.Errorf("Configs not equal: %+v != %+v", config, testData.config) } - if !cmp.Equal(config.IgnoredPackageVersions, testData.config.IgnoredPackageVersions) { + if !cmp.Equal(config.PackageVersions, testData.config.PackageVersions) { t.Errorf("Configs not equal: %+v != %+v", config, testData.config) } if testData.configHasErr { @@ -225,18 +227,19 @@ func TestConfig_ShouldIgnorePackageVersion(t *testing.T) { config Config args args wantOk bool - wantEntry IgnorePackageVersionEntry + wantEntry PackageVersionEntry }{ { name: "Version-level entry exists", config: Config{ - IgnoredPackageVersions: []IgnorePackageVersionEntry{ + PackageVersions: []PackageVersionEntry{ { - Name: "lib1", - Version: "1.0.0", - Ecosystem: "Go", - IgnoreUntil: time.Time{}, - Reason: "abc", + Name: "lib1", + Version: "1.0.0", + Ecosystem: "Go", + Ignore: true, + EffectiveUntil: time.Time{}, + Reason: "abc", }, }, }, @@ -246,23 +249,25 @@ func TestConfig_ShouldIgnorePackageVersion(t *testing.T) { ecosystem: "Go", }, wantOk: true, - wantEntry: IgnorePackageVersionEntry{ - Name: "lib1", - Version: "1.0.0", - Ecosystem: "Go", - IgnoreUntil: time.Time{}, - Reason: "abc", + wantEntry: PackageVersionEntry{ + Name: "lib1", + Version: "1.0.0", + Ecosystem: "Go", + Ignore: true, + EffectiveUntil: time.Time{}, + Reason: "abc", }, }, { name: "Package-level entry exists", config: Config{ - IgnoredPackageVersions: []IgnorePackageVersionEntry{ + PackageVersions: []PackageVersionEntry{ { - Name: "lib1", - Ecosystem: "Go", - IgnoreUntil: time.Time{}, - Reason: "abc", + Name: "lib1", + Ecosystem: "Go", + Ignore: true, + EffectiveUntil: time.Time{}, + Reason: "abc", }, }, }, @@ -272,30 +277,33 @@ func TestConfig_ShouldIgnorePackageVersion(t *testing.T) { ecosystem: "Go", }, wantOk: true, - wantEntry: IgnorePackageVersionEntry{ - Name: "lib1", - Ecosystem: "Go", - IgnoreUntil: time.Time{}, - Reason: "abc", + wantEntry: PackageVersionEntry{ + Name: "lib1", + Ecosystem: "Go", + Ignore: true, + EffectiveUntil: time.Time{}, + Reason: "abc", }, }, { - name: "Entry doesn't exists", + name: "Entry doesn't exist", config: Config{ - IgnoredPackageVersions: []IgnorePackageVersionEntry{ + PackageVersions: []PackageVersionEntry{ { - Name: "lib1", - Version: "1.0.0", - Ecosystem: "Go", - IgnoreUntil: time.Time{}, - Reason: "abc", + Name: "lib1", + Version: "2.0.0", + Ecosystem: "Go", + Ignore: false, + EffectiveUntil: time.Time{}, + Reason: "abc", }, { - Name: "lib2", - Version: "2.0.0", - Ecosystem: "Go", - IgnoreUntil: time.Time{}, - Reason: "abc", + Name: "lib2", + Version: "2.0.0", + Ignore: true, + Ecosystem: "Go", + EffectiveUntil: time.Time{}, + Reason: "abc", }, }, }, @@ -305,7 +313,7 @@ func TestConfig_ShouldIgnorePackageVersion(t *testing.T) { ecosystem: "Go", }, wantOk: false, - wantEntry: IgnorePackageVersionEntry{}, + wantEntry: PackageVersionEntry{}, }, } @@ -338,18 +346,20 @@ func TestConfig_ShouldOverridePackageVersionLicense(t *testing.T) { config Config args args wantOk bool - wantEntry OverridePackageVersionLicenseEntry + wantEntry PackageVersionEntry }{ { name: "Exact version entry exists", config: Config{ - OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ + PackageVersions: []PackageVersionEntry{ { - Name: "lib1", - ExactVersion: "1.0.0", - Ecosystem: "Go", - LicenseOverride: []string{"mit"}, - Reason: "abc", + Name: "lib1", + Version: "1.0.0", + Ecosystem: "Go", + License: License{ + Override: []string{"mit"}, + }, + Reason: "abc", }, }, }, @@ -359,156 +369,28 @@ func TestConfig_ShouldOverridePackageVersionLicense(t *testing.T) { ecosystem: "Go", }, wantOk: true, - wantEntry: OverridePackageVersionLicenseEntry{ - Name: "lib1", - ExactVersion: "1.0.0", - Ecosystem: "Go", - LicenseOverride: []string{"mit"}, - Reason: "abc", - }, - }, - { - name: "Exact version entry doesn't exist", - config: Config{ - OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ - { - Name: "lib1", - ExactVersion: "1.0.0", - Ecosystem: "Go", - LicenseOverride: []string{"mit"}, - Reason: "abc", - }, - }, - }, - args: args{ - name: "lib1", - version: "1.0.1", - ecosystem: "Go", - }, - wantOk: false, - wantEntry: OverridePackageVersionLicenseEntry{}, - }, - { - name: "Major version matches", - config: Config{ - OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ - { - Name: "lib1", - Major: "1", - Ecosystem: "Go", - LicenseOverride: []string{"mit"}, - Reason: "abc", - }, - }, - }, - args: args{ - name: "lib1", - version: "1.0.1", - ecosystem: "Go", - }, - wantOk: true, - wantEntry: OverridePackageVersionLicenseEntry{ - Name: "lib1", - Major: "1", - Ecosystem: "Go", - LicenseOverride: []string{"mit"}, - Reason: "abc", - }, - }, - { - name: "Major and minor version matches", - config: Config{ - OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ - { - Name: "lib1", - Major: "1", - Minor: "0", - Ecosystem: "Go", - LicenseOverride: []string{"mit"}, - Reason: "abc", - }, - }, - }, - args: args{ - name: "lib1", - version: "1.0.1", - ecosystem: "Go", - }, - wantOk: true, - wantEntry: OverridePackageVersionLicenseEntry{ - Name: "lib1", - Major: "1", - Minor: "0", - Ecosystem: "Go", - LicenseOverride: []string{"mit"}, - Reason: "abc", - }, - }, - { - name: "Major, minor and patch version matches", - config: Config{ - OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ - { - Name: "lib1", - Major: "1", - Minor: "0", - Patch: "1", - Ecosystem: "Go", - LicenseOverride: []string{"mit"}, - Reason: "abc", - }, - }, - }, - args: args{ - name: "lib1", - version: "1.0.1", - ecosystem: "Go", - }, - wantOk: true, - wantEntry: OverridePackageVersionLicenseEntry{ - Name: "lib1", - Major: "1", - Minor: "0", - Patch: "1", - Ecosystem: "Go", - LicenseOverride: []string{"mit"}, - Reason: "abc", - }, - }, - { - name: "Major matches, minor doesn't", - config: Config{ - OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ - { - Name: "lib1", - Major: "1", - Minor: "2", - Ecosystem: "Go", - LicenseOverride: []string{"mit"}, - Reason: "abc", - }, + wantEntry: PackageVersionEntry{ + Name: "lib1", + Version: "1.0.0", + Ecosystem: "Go", + License: License{ + Override: []string{"mit"}, }, + Reason: "abc", }, - args: args{ - name: "lib1", - version: "1.0.1", - ecosystem: "Go", - }, - wantOk: false, - wantEntry: OverridePackageVersionLicenseEntry{}, }, { - name: "Major and minor matches, patch doesn't", + name: "Version entry doesn't exist", config: Config{ - OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ + PackageVersions: []PackageVersionEntry{ { - Name: "lib1", - Major: "1", - Minor: "0", - Patch: "3", - Ecosystem: "Go", - LicenseOverride: []string{"mit"}, - Reason: "abc", + Name: "lib1", + Version: "1.0.0", + Ecosystem: "Go", + License: License{ + Override: []string{"mit"}, + }, + Reason: "abc", }, }, }, @@ -518,17 +400,19 @@ func TestConfig_ShouldOverridePackageVersionLicense(t *testing.T) { ecosystem: "Go", }, wantOk: false, - wantEntry: OverridePackageVersionLicenseEntry{}, + wantEntry: PackageVersionEntry{}, }, { name: "Name matches", config: Config{ - OverridePackageVersionLicenses: []OverridePackageVersionLicenseEntry{ + PackageVersions: []PackageVersionEntry{ { - Name: "lib1", - Ecosystem: "Go", - LicenseOverride: []string{"mit"}, - Reason: "abc", + Name: "lib1", + Ecosystem: "Go", + License: License{ + Override: []string{"mit"}, + }, + Reason: "abc", }, }, }, @@ -538,11 +422,13 @@ func TestConfig_ShouldOverridePackageVersionLicense(t *testing.T) { ecosystem: "Go", }, wantOk: true, - wantEntry: OverridePackageVersionLicenseEntry{ - Name: "lib1", - Ecosystem: "Go", - LicenseOverride: []string{"mit"}, - Reason: "abc", + wantEntry: PackageVersionEntry{ + Name: "lib1", + Ecosystem: "Go", + License: License{ + Override: []string{"mit"}, + }, + Reason: "abc", }, }, } diff --git a/pkg/osvscanner/vulnerability_result_internal_test.go b/pkg/osvscanner/vulnerability_result_internal_test.go index f3453cfeb8..cb2aedd2c0 100644 --- a/pkg/osvscanner/vulnerability_result_internal_test.go +++ b/pkg/osvscanner/vulnerability_result_internal_test.go @@ -180,7 +180,7 @@ func Test_assembleResult(t *testing.T) { }, }, }, { - name: "group_vulnerabilities,_with_license_allowlist_and_all_packages", + name: "group_vulnerabilities_with_license_allowlist_and_all_packages", args: args{ r: &reporter.VoidReporter{}, packages: packages, @@ -205,12 +205,3 @@ func Test_assembleResult(t *testing.T) { }) } } - -func makeLicenses(strLicenses []string) []models.License { - licenses := make([]models.License, len(strLicenses)) - for i, l := range strLicenses { - licenses[i] = models.License(l) - } - - return licenses -} From 95efa12f98257e7e32b38cba0bc1ec817d690d02 Mon Sep 17 00:00:00 2001 From: Josie Anugerah Date: Tue, 7 May 2024 11:11:39 +1000 Subject: [PATCH 5/7] snapshot --- .../vulnerability_result_internal_test.snap | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/pkg/osvscanner/__snapshots__/vulnerability_result_internal_test.snap b/pkg/osvscanner/__snapshots__/vulnerability_result_internal_test.snap index c13d95b957..9d7d7001d5 100755 --- a/pkg/osvscanner/__snapshots__/vulnerability_result_internal_test.snap +++ b/pkg/osvscanner/__snapshots__/vulnerability_result_internal_test.snap @@ -85,7 +85,7 @@ } --- -[Test_assembleResult/group_vulnerabilities,_with_license_allowlist_and_all_packages - 1] +[Test_assembleResult/group_vulnerabilities_with_all_packages_included - 1] { "results": [ { @@ -125,10 +125,6 @@ ], "max_severity": "" } - ], - "licenses": [ - "MIT", - "0BSD" ] }, { @@ -136,10 +132,7 @@ "name": "pkg-2", "version": "1.0.0", "ecosystem": "npm" - }, - "licenses": [ - "MIT" - ] + } } ] }, @@ -171,12 +164,6 @@ ], "max_severity": "" } - ], - "licenses": [ - "UNKNOWN" - ], - "license_violations": [ - "UNKNOWN" ] } ] @@ -185,16 +172,13 @@ "experimental_config": { "licenses": { "summary": false, - "allowlist": [ - "MIT", - "0BSD" - ] + "allowlist": null } } } --- -[Test_assembleResult/group_vulnerabilities_with_all_packages_included - 1] +[Test_assembleResult/group_vulnerabilities_with_license_allowlist - 1] { "results": [ { @@ -234,14 +218,11 @@ ], "max_severity": "" } + ], + "licenses": [ + "MIT", + "0BSD" ] - }, - { - "package": { - "name": "pkg-2", - "version": "1.0.0", - "ecosystem": "npm" - } } ] }, @@ -273,6 +254,12 @@ ], "max_severity": "" } + ], + "licenses": [ + "UNKNOWN" + ], + "license_violations": [ + "UNKNOWN" ] } ] @@ -281,13 +268,16 @@ "experimental_config": { "licenses": { "summary": false, - "allowlist": null + "allowlist": [ + "MIT", + "0BSD" + ] } } } --- -[Test_assembleResult/group_vulnerabilities_with_license_allowlist - 1] +[Test_assembleResult/group_vulnerabilities_with_license_allowlist_and_all_packages - 1] { "results": [ { @@ -332,6 +322,16 @@ "MIT", "0BSD" ] + }, + { + "package": { + "name": "pkg-2", + "version": "1.0.0", + "ecosystem": "npm" + }, + "licenses": [ + "MIT" + ] } ] }, From cf09e1922c7ab2a9f6db5b050db2797e88bf865b Mon Sep 17 00:00:00 2001 From: Josie Anugerah Date: Thu, 6 Jun 2024 14:09:29 +1000 Subject: [PATCH 6/7] rename PackageOverrides --- fixtures/testdatainner/osv-scanner.toml | 4 +-- .../__snapshots__/integration_test.snap | 21 ++++++------ pkg/config/config.go | 26 +++++++-------- pkg/config/config_internal_test.go | 32 +++++++++---------- .../vulnerability_result_internal_test.go | 2 +- 5 files changed, 43 insertions(+), 42 deletions(-) diff --git a/fixtures/testdatainner/osv-scanner.toml b/fixtures/testdatainner/osv-scanner.toml index 52b1a667e7..f9be2c0f2e 100644 --- a/fixtures/testdatainner/osv-scanner.toml +++ b/fixtures/testdatainner/osv-scanner.toml @@ -8,7 +8,7 @@ id = "GO-2022-1059" # ignoreUntil = 2022-11-09 # Optional exception expiry date # reason = "" # Optional reason -[[PackageVersions]] +[[PackageOverrides]] name = "lib" version = "1.0.0" ecosystem = "Go" @@ -16,7 +16,7 @@ ignore = true # effectiveUntil = 2022-11-09 # Optional exception expiry date reason = "abc" -[[PackageVersions]] +[[PackageOverrides]] name = "my-pkg" version = "1.0.0" ecosystem = "Go" diff --git a/internal/sourceanalysis/__snapshots__/integration_test.snap b/internal/sourceanalysis/__snapshots__/integration_test.snap index 7ceccb1441..c119cd546d 100755 --- a/internal/sourceanalysis/__snapshots__/integration_test.snap +++ b/internal/sourceanalysis/__snapshots__/integration_test.snap @@ -1,3 +1,4 @@ + [Test_runGovulncheck - 1] { "GO-2021-0053": [ @@ -124,7 +125,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 839, + "line": 840, "column": 21 } }, @@ -137,7 +138,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 1038, + "line": 1039, "column": 24 } }, @@ -149,7 +150,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 430, + "line": 429, "column": 21 } }, @@ -161,7 +162,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 389, + "line": 388, "column": 19 } }, @@ -174,7 +175,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 1002, + "line": 1003, "column": 19 } }, @@ -187,7 +188,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 1670, + "line": 1675, "column": 17 } }, @@ -200,7 +201,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 2015, + "line": 2045, "column": 18 } }, @@ -213,7 +214,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 3086, + "line": 3285, "column": 3 } }, @@ -226,7 +227,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 2985, + "line": 3184, "column": 18 } }, @@ -238,7 +239,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 3239, + "line": 3438, "column": 30 } }, diff --git a/pkg/config/config.go b/pkg/config/config.go index 814b501251..cff4e40b6f 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -23,10 +23,10 @@ type ConfigManager struct { } type Config struct { - IgnoredVulns []IgnoreEntry `toml:"IgnoredVulns"` - PackageVersions []PackageVersionEntry `toml:"PackageVersions"` - LoadPath string `toml:"LoadPath"` - GoVersionOverride string `toml:"GoVersionOverride"` + IgnoredVulns []IgnoreEntry `toml:"IgnoredVulns"` + PackageOverrides []PackageOverrideEntry `toml:"PackageOverrides"` + LoadPath string `toml:"LoadPath"` + GoVersionOverride string `toml:"GoVersionOverride"` } type IgnoreEntry struct { @@ -35,7 +35,7 @@ type IgnoreEntry struct { Reason string `toml:"reason"` } -type PackageVersionEntry struct { +type PackageOverrideEntry struct { Name string `toml:"name"` // If the version is empty, the entry applies to all versions. Version string `toml:"version"` @@ -60,8 +60,8 @@ func (c *Config) ShouldIgnore(vulnID string) (bool, IgnoreEntry) { return shouldIgnoreTimestamp(ignoredLine.IgnoreUntil), ignoredLine } -func (c *Config) filterPackageVersionEntries(name string, version string, ecosystem string, condition func(PackageVersionEntry) bool) (bool, PackageVersionEntry) { - index := slices.IndexFunc(c.PackageVersions, func(e PackageVersionEntry) bool { +func (c *Config) filterPackageVersionEntries(name string, version string, ecosystem string, condition func(PackageOverrideEntry) bool) (bool, PackageOverrideEntry) { + index := slices.IndexFunc(c.PackageOverrides, func(e PackageOverrideEntry) bool { if ecosystem != e.Ecosystem || name != e.Name { return false } @@ -69,21 +69,21 @@ func (c *Config) filterPackageVersionEntries(name string, version string, ecosys return (version == e.Version || e.Version == "") && condition(e) }) if index == -1 { - return false, PackageVersionEntry{} + return false, PackageOverrideEntry{} } - ignoredLine := c.PackageVersions[index] + ignoredLine := c.PackageOverrides[index] return shouldIgnoreTimestamp(ignoredLine.EffectiveUntil), ignoredLine } -func (c *Config) ShouldIgnorePackageVersion(name, version, ecosystem string) (bool, PackageVersionEntry) { - return c.filterPackageVersionEntries(name, version, ecosystem, func(e PackageVersionEntry) bool { +func (c *Config) ShouldIgnorePackageVersion(name, version, ecosystem string) (bool, PackageOverrideEntry) { + return c.filterPackageVersionEntries(name, version, ecosystem, func(e PackageOverrideEntry) bool { return e.Ignore }) } -func (c *Config) ShouldOverridePackageVersionLicense(name, version, ecosystem string) (bool, PackageVersionEntry) { - return c.filterPackageVersionEntries(name, version, ecosystem, func(e PackageVersionEntry) bool { +func (c *Config) ShouldOverridePackageVersionLicense(name, version, ecosystem string) (bool, PackageOverrideEntry) { + return c.filterPackageVersionEntries(name, version, ecosystem, func(e PackageOverrideEntry) bool { return len(e.License.Override) > 0 }) } diff --git a/pkg/config/config_internal_test.go b/pkg/config/config_internal_test.go index 0381042356..4663933e10 100644 --- a/pkg/config/config_internal_test.go +++ b/pkg/config/config_internal_test.go @@ -27,7 +27,7 @@ func TestTryLoadConfig(t *testing.T) { ID: "GO-2022-1059", }, }, - PackageVersions: []PackageVersionEntry{ + PackageOverrides: []PackageOverrideEntry{ { Name: "lib", Version: "1.0.0", @@ -88,7 +88,7 @@ func TestTryLoadConfig(t *testing.T) { if !cmp.Equal(config.IgnoredVulns, testData.config.IgnoredVulns) { t.Errorf("Configs not equal: %+v != %+v", config, testData.config) } - if !cmp.Equal(config.PackageVersions, testData.config.PackageVersions) { + if !cmp.Equal(config.PackageOverrides, testData.config.PackageOverrides) { t.Errorf("Configs not equal: %+v != %+v", config, testData.config) } if testData.configHasErr { @@ -227,12 +227,12 @@ func TestConfig_ShouldIgnorePackageVersion(t *testing.T) { config Config args args wantOk bool - wantEntry PackageVersionEntry + wantEntry PackageOverrideEntry }{ { name: "Version-level entry exists", config: Config{ - PackageVersions: []PackageVersionEntry{ + PackageOverrides: []PackageOverrideEntry{ { Name: "lib1", Version: "1.0.0", @@ -249,7 +249,7 @@ func TestConfig_ShouldIgnorePackageVersion(t *testing.T) { ecosystem: "Go", }, wantOk: true, - wantEntry: PackageVersionEntry{ + wantEntry: PackageOverrideEntry{ Name: "lib1", Version: "1.0.0", Ecosystem: "Go", @@ -261,7 +261,7 @@ func TestConfig_ShouldIgnorePackageVersion(t *testing.T) { { name: "Package-level entry exists", config: Config{ - PackageVersions: []PackageVersionEntry{ + PackageOverrides: []PackageOverrideEntry{ { Name: "lib1", Ecosystem: "Go", @@ -277,7 +277,7 @@ func TestConfig_ShouldIgnorePackageVersion(t *testing.T) { ecosystem: "Go", }, wantOk: true, - wantEntry: PackageVersionEntry{ + wantEntry: PackageOverrideEntry{ Name: "lib1", Ecosystem: "Go", Ignore: true, @@ -288,7 +288,7 @@ func TestConfig_ShouldIgnorePackageVersion(t *testing.T) { { name: "Entry doesn't exist", config: Config{ - PackageVersions: []PackageVersionEntry{ + PackageOverrides: []PackageOverrideEntry{ { Name: "lib1", Version: "2.0.0", @@ -313,7 +313,7 @@ func TestConfig_ShouldIgnorePackageVersion(t *testing.T) { ecosystem: "Go", }, wantOk: false, - wantEntry: PackageVersionEntry{}, + wantEntry: PackageOverrideEntry{}, }, } @@ -346,12 +346,12 @@ func TestConfig_ShouldOverridePackageVersionLicense(t *testing.T) { config Config args args wantOk bool - wantEntry PackageVersionEntry + wantEntry PackageOverrideEntry }{ { name: "Exact version entry exists", config: Config{ - PackageVersions: []PackageVersionEntry{ + PackageOverrides: []PackageOverrideEntry{ { Name: "lib1", Version: "1.0.0", @@ -369,7 +369,7 @@ func TestConfig_ShouldOverridePackageVersionLicense(t *testing.T) { ecosystem: "Go", }, wantOk: true, - wantEntry: PackageVersionEntry{ + wantEntry: PackageOverrideEntry{ Name: "lib1", Version: "1.0.0", Ecosystem: "Go", @@ -382,7 +382,7 @@ func TestConfig_ShouldOverridePackageVersionLicense(t *testing.T) { { name: "Version entry doesn't exist", config: Config{ - PackageVersions: []PackageVersionEntry{ + PackageOverrides: []PackageOverrideEntry{ { Name: "lib1", Version: "1.0.0", @@ -400,12 +400,12 @@ func TestConfig_ShouldOverridePackageVersionLicense(t *testing.T) { ecosystem: "Go", }, wantOk: false, - wantEntry: PackageVersionEntry{}, + wantEntry: PackageOverrideEntry{}, }, { name: "Name matches", config: Config{ - PackageVersions: []PackageVersionEntry{ + PackageOverrides: []PackageOverrideEntry{ { Name: "lib1", Ecosystem: "Go", @@ -422,7 +422,7 @@ func TestConfig_ShouldOverridePackageVersionLicense(t *testing.T) { ecosystem: "Go", }, wantOk: true, - wantEntry: PackageVersionEntry{ + wantEntry: PackageOverrideEntry{ Name: "lib1", Ecosystem: "Go", License: License{ diff --git a/pkg/osvscanner/vulnerability_result_internal_test.go b/pkg/osvscanner/vulnerability_result_internal_test.go index cb2aedd2c0..a26ceed90f 100644 --- a/pkg/osvscanner/vulnerability_result_internal_test.go +++ b/pkg/osvscanner/vulnerability_result_internal_test.go @@ -167,7 +167,7 @@ func Test_assembleResult(t *testing.T) { }, config: &config.ConfigManager{ OverrideConfig: &config.Config{ - PackageVersions: []config.PackageVersionEntry{ + PackageOverrides: []config.PackageOverrideEntry{ { Name: "pkg-3", Ecosystem: "npm", From 78fe74df59864017f89cc065bf1e284fbdd5b9cf Mon Sep 17 00:00:00 2001 From: Josie Anugerah Date: Thu, 6 Jun 2024 14:36:09 +1000 Subject: [PATCH 7/7] revert snapshot file --- .../__snapshots__/integration_test.snap | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/internal/sourceanalysis/__snapshots__/integration_test.snap b/internal/sourceanalysis/__snapshots__/integration_test.snap index c119cd546d..7ceccb1441 100755 --- a/internal/sourceanalysis/__snapshots__/integration_test.snap +++ b/internal/sourceanalysis/__snapshots__/integration_test.snap @@ -1,4 +1,3 @@ - [Test_runGovulncheck - 1] { "GO-2021-0053": [ @@ -125,7 +124,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 840, + "line": 839, "column": 21 } }, @@ -138,7 +137,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 1039, + "line": 1038, "column": 24 } }, @@ -150,7 +149,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 429, + "line": 430, "column": 21 } }, @@ -162,7 +161,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 388, + "line": 389, "column": 19 } }, @@ -175,7 +174,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 1003, + "line": 1002, "column": 19 } }, @@ -188,7 +187,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 1675, + "line": 1670, "column": 17 } }, @@ -201,7 +200,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 2045, + "line": 2015, "column": 18 } }, @@ -214,7 +213,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 3285, + "line": 3086, "column": 3 } }, @@ -227,7 +226,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 3184, + "line": 2985, "column": 18 } }, @@ -239,7 +238,7 @@ "position": { "filename": "\u003cAny value\u003e", "offset": -1, - "line": 3438, + "line": 3239, "column": 30 } },