diff --git a/CHANGELOG.md b/CHANGELOG.md index 227e1f0991..832a18f53c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,48 @@ +OSV-Scanner v2 is coming soon! The next release will start with version `v2.0.0-alpha1`. + +Here's a peek at some of the exciting upcoming features: + +- Standalone container image scanning support. + - Including support for Alpine and Debian images. +- Refactored internals to use [`osv-scalibr`](https://github.com/google/osv-scalibr) library for better extraction capabilities. +- HTML output format for clearer vulnerability results. +- More control over output format and logging. +- ...and more! + +Importantly, the CLI interface of osv-scanner will be maintained with minimal breaking changes. +Most breaking changes will only be in the API. More details in the upcoming alpha release. + +--- + +This is the final feature v1 release of osv-scanner, future releases for v1 will only contain bug fixes. + +# v1.9.1 + +### Features: + +- [Feature #1295](https://github.com/google/osv-scanner/pull/1295) Support offline database in fix subcommand. +- [Feature #1342](https://github.com/google/osv-scanner/pull/1342) Add `--experimental-offline-vulnerabilities` and `--experimental-no-resolve` flags. +- [Feature #1045](https://github.com/google/osv-scanner/pull/1045) Support private registries for Maven. +- [Feature #1226](https://github.com/google/osv-scanner/pull/1226) Support support `vulnerabilities.ignore` in package overrides. + +### Fixes: + +- [Bug #604](https://github.com/google/osv-scanner/pull/604) Use correct path separator in SARIF output when on Windows. +- [Bug #330](https://github.com/google/osv-scanner/pull/330) Warn about and ignore duplicate entries in SBOMs. +- [Bug #1325](https://github.com/google/osv-scanner/pull/1325) Set CharsetReader and Entity when reading pom.xml. +- [Bug #1310](https://github.com/google/osv-scanner/pull/1310) Update spdx license ids. +- [Bug #1288](https://github.com/google/osv-scanner/pull/1288) Sort sbom packages by PURL. +- [Bug #1285](https://github.com/google/osv-scanner/pull/1285) Improve handling if `docker` exits with a non-zero code when trying to scan images + +### API Changes: + +- Deprecate auxillary public packages: As part of the V2 update described above, we have started deprecating some of the auxillary packages + which are not commonly used to give us more room to make better API designs. These include: + - `config` + - `depsdev` + - `grouper` + - `spdx` + # v1.9.0 ### Features: diff --git a/cmd/osv-scanner/__snapshots__/main_test.snap b/cmd/osv-scanner/__snapshots__/main_test.snap index 6e7937416b..1d0d9c5178 100755 --- a/cmd/osv-scanner/__snapshots__/main_test.snap +++ b/cmd/osv-scanner/__snapshots__/main_test.snap @@ -80,7 +80,7 @@ Loaded filter from: /fixtures/locks-many/osv-scanner.toml "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -234,7 +234,7 @@ Loaded Alpine local db from /osv-scanner/Alpine/all.zip } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -850,7 +850,7 @@ No issues found --- [TestRun/version - 1] -osv-scanner version: 1.9.0 +osv-scanner version: 1.9.1 commit: n/a built at: n/a @@ -1035,7 +1035,7 @@ Scanned /fixtures/locks-insecure/osv-scanner-flutter-deps.json file as } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -1857,6 +1857,7 @@ Filtered 16 vulnerabilities from output | https://osv.dev/DLA-3449-1 | | Debian | openssl | 1.1.0l-1~deb9u5 | fixtures/sbom-insecure/postgres-stretch.cdx.xml | | https://osv.dev/DLA-3530-1 | | Debian | openssl | 1.1.0l-1~deb9u5 | fixtures/sbom-insecure/postgres-stretch.cdx.xml | | https://osv.dev/DLA-3942-1 | | Debian | openssl | 1.1.0l-1~deb9u5 | fixtures/sbom-insecure/postgres-stretch.cdx.xml | +| https://osv.dev/DLA-3942-2 | | Debian | openssl | 1.1.0l-1~deb9u5 | fixtures/sbom-insecure/postgres-stretch.cdx.xml | | https://osv.dev/DSA-4539-3 | | Debian | openssl | 1.1.0l-1~deb9u5 | fixtures/sbom-insecure/postgres-stretch.cdx.xml | | https://osv.dev/CVE-2017-12837 | 7.5 | Debian | perl | 5.24.1-3+deb9u7 | fixtures/sbom-insecure/postgres-stretch.cdx.xml | | https://osv.dev/CVE-2017-12883 | 9.1 | Debian | perl | 5.24.1-3+deb9u7 | fixtures/sbom-insecure/postgres-stretch.cdx.xml | @@ -2036,6 +2037,7 @@ Filtered 16 vulnerabilities from output | https://osv.dev/DLA-3449-1 | | Debian | openssl | 1.1.0l-1~deb9u5 | fixtures/sbom-insecure/postgres-stretch.cdx.xml | | https://osv.dev/DLA-3530-1 | | Debian | openssl | 1.1.0l-1~deb9u5 | fixtures/sbom-insecure/postgres-stretch.cdx.xml | | https://osv.dev/DLA-3942-1 | | Debian | openssl | 1.1.0l-1~deb9u5 | fixtures/sbom-insecure/postgres-stretch.cdx.xml | +| https://osv.dev/DLA-3942-2 | | Debian | openssl | 1.1.0l-1~deb9u5 | fixtures/sbom-insecure/postgres-stretch.cdx.xml | | https://osv.dev/DSA-4539-3 | | Debian | openssl | 1.1.0l-1~deb9u5 | fixtures/sbom-insecure/postgres-stretch.cdx.xml | | https://osv.dev/CVE-2017-12837 | 7.5 | Debian | perl | 5.24.1-3+deb9u7 | fixtures/sbom-insecure/postgres-stretch.cdx.xml | | https://osv.dev/CVE-2017-12883 | 9.1 | Debian | perl | 5.24.1-3+deb9u7 | fixtures/sbom-insecure/postgres-stretch.cdx.xml | diff --git a/docs/github-action.md b/docs/github-action.md index 3460e43aba..c28acdffd0 100644 --- a/docs/github-action.md +++ b/docs/github-action.md @@ -55,7 +55,7 @@ permissions: jobs: scan-pr: - uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@v1.9.0" + uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@v1.9.1" ``` ### View results @@ -98,7 +98,7 @@ permissions: jobs: scan-scheduled: - uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@v1.9.0" + uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@v1.9.1" ``` As written, the scanner will run on 12:30 pm UTC every Monday, and also on every push to the main branch. You can change the schedule by following the instructions [here](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule). @@ -133,7 +133,7 @@ permissions: jobs: osv-scan: - uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@v1.9.0" + uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@v1.9.1" with: # Only scan the top level go.mod file without recursively scanning directories since # this is pipeline is about releasing the go module and binary @@ -163,7 +163,7 @@ Results may be viewed by clicking on the details of the failed release action fr The GitHub Actions have the following optional inputs: -- `scan-args`: This value is passed to `osv-scanner` CLI after being split by each line. See the [usage](./usage) page for the available options. The `--format` and `--output` flags are already set by the reusable workflow and should not be overridden here. +- `scan-args`: This value is passed to `osv-scanner` CLI after being split by each line. See the [usage](./usage.md) page for the available options. The `--format` and `--output` flags are already set by the reusable workflow and should not be overridden here. Default: ```bash --recursive # Recursively scan subdirectories @@ -172,7 +172,7 @@ The GitHub Actions have the following optional inputs: ``` - `results-file-name`: This is the name of the final SARIF file uploaded to Github. Default: `results.sarif` -- `download-artifact`: Optional artifact to download for scanning. Can be used if you need to do some preprocessing to prepare the lockfiles for scanning. If the file names in the artifact are not standard lockfile names, make sure to add custom scan-args to specify the lockfile type and path (see [specify lockfiles](./usage#specify-lockfiles)). +- `download-artifact`: Optional artifact to download for scanning. Can be used if you need to do some preprocessing to prepare the lockfiles for scanning. If the file names in the artifact are not standard lockfile names, make sure to add custom scan-args to specify the lockfile type and path (see [specify lockfiles](./usage.md#specify-lockfiles)). - `upload-sarif`: Whether to upload the results to Security > Code Scanning. Defaults to `true`. - `fail-on-vuln`: Whether to fail the workflow when a vulnerability is found. Defaults to `true`. @@ -186,7 +186,7 @@ Examples ```yml jobs: scan-pr: - uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@v1.9.0" + uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@v1.9.1" with: scan-args: |- --lockfile=./path/to/lockfile1 @@ -198,7 +198,7 @@ jobs: ```yml jobs: scan-pr: - uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@v1.9.0" + uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@v1.9.1" with: scan-args: |- --recursive @@ -225,7 +225,7 @@ jobs: name: Vulnerability scanning # makes sure the extraction step is completed before running the scanner needs: extract-deps - uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@v1.9.0" + uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@v1.9.1" with: # Download the artifact uploaded in extract-deps step download-artifact: converted-OSV-Scanner-deps diff --git a/internal/config/config.go b/internal/config/config.go index d1b8b86b0c..afa7abbf13 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -16,11 +16,7 @@ import ( const osvScannerConfigName = "osv-scanner.toml" -// Ignore stuttering as that would be a breaking change -// TODO: V2 rename? -// -//nolint:revive -type ConfigManager struct { +type Manager struct { // Override to replace all other configs OverrideConfig *Config // Config to use if no config file is found alongside manifests @@ -112,17 +108,6 @@ func (c *Config) ShouldIgnorePackage(pkg models.PackageVulns) (bool, PackageOver }) } -// Deprecated: Use ShouldIgnorePackage instead -func (c *Config) ShouldIgnorePackageVersion(name, version, ecosystem string) (bool, PackageOverrideEntry) { - return c.ShouldIgnorePackage(models.PackageVulns{ - Package: models.PackageInfo{ - Name: name, - Version: version, - Ecosystem: ecosystem, - }, - }) -} - // ShouldIgnorePackageVulnerabilities determines if the given package should have its vulnerabilities ignored based on override entries in the config func (c *Config) ShouldIgnorePackageVulnerabilities(pkg models.PackageVulns) bool { overrides, _ := c.filterPackageVersionEntries(pkg, func(e PackageOverrideEntry) bool { @@ -139,17 +124,6 @@ func (c *Config) ShouldOverridePackageLicense(pkg models.PackageVulns) (bool, Pa }) } -// Deprecated: Use ShouldOverridePackageLicense instead -func (c *Config) ShouldOverridePackageVersionLicense(name, version, ecosystem string) (bool, PackageOverrideEntry) { - return c.ShouldOverridePackageLicense(models.PackageVulns{ - Package: models.PackageInfo{ - Name: name, - Version: version, - Ecosystem: ecosystem, - }, - }) -} - func shouldIgnoreTimestamp(ignoreUntil time.Time) bool { if ignoreUntil.IsZero() { // If IgnoreUntil is not set, should ignore. @@ -162,7 +136,7 @@ func shouldIgnoreTimestamp(ignoreUntil time.Time) bool { // Sets the override config by reading the config file at configPath. // Will return an error if loading the config file fails -func (c *ConfigManager) UseOverride(configPath string) error { +func (c *Manager) UseOverride(configPath string) error { config, configErr := tryLoadConfig(configPath) if configErr != nil { return configErr @@ -173,7 +147,7 @@ func (c *ConfigManager) UseOverride(configPath string) error { } // Attempts to get the config -func (c *ConfigManager) Get(r reporter.Reporter, targetPath string) Config { +func (c *Manager) Get(r reporter.Reporter, targetPath string) Config { if c.OverrideConfig != nil { return *c.OverrideConfig } diff --git a/internal/config/config_internal_test.go b/internal/config/config_internal_test.go index 2336c2ae23..fd2c8cd4a4 100644 --- a/internal/config/config_internal_test.go +++ b/internal/config/config_internal_test.go @@ -787,124 +787,6 @@ func TestConfig_ShouldIgnorePackage(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 PackageOverrideEntry - }{ - { - name: "Version-level entry exists", - config: Config{ - PackageOverrides: []PackageOverrideEntry{ - { - Name: "lib1", - Version: "1.0.0", - Ecosystem: "Go", - Ignore: true, - EffectiveUntil: time.Time{}, - Reason: "abc", - }, - }, - }, - args: args{ - name: "lib1", - version: "1.0.0", - ecosystem: "Go", - }, - wantOk: true, - wantEntry: PackageOverrideEntry{ - Name: "lib1", - Version: "1.0.0", - Ecosystem: "Go", - Ignore: true, - EffectiveUntil: time.Time{}, - Reason: "abc", - }, - }, - { - name: "Package-level entry exists", - config: Config{ - PackageOverrides: []PackageOverrideEntry{ - { - Name: "lib1", - Ecosystem: "Go", - Ignore: true, - EffectiveUntil: time.Time{}, - Reason: "abc", - }, - }, - }, - args: args{ - name: "lib1", - version: "1.0.0", - ecosystem: "Go", - }, - wantOk: true, - wantEntry: PackageOverrideEntry{ - Name: "lib1", - Ecosystem: "Go", - Ignore: true, - EffectiveUntil: time.Time{}, - Reason: "abc", - }, - }, - { - name: "Entry doesn't exist", - config: Config{ - PackageOverrides: []PackageOverrideEntry{ - { - Name: "lib1", - Version: "2.0.0", - Ecosystem: "Go", - Ignore: false, - EffectiveUntil: time.Time{}, - Reason: "abc", - }, - { - Name: "lib2", - Version: "2.0.0", - Ignore: true, - Ecosystem: "Go", - EffectiveUntil: time.Time{}, - Reason: "abc", - }, - }, - }, - args: args{ - name: "lib1", - version: "2.0.0", - ecosystem: "Go", - }, - wantOk: false, - wantEntry: PackageOverrideEntry{}, - }, - } - - for _, tt := range tests { - 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) - } - }) - } -} - func TestConfig_ShouldIgnorePackageVulnerabilities(t *testing.T) { t.Parallel() @@ -1203,118 +1085,3 @@ func TestConfig_ShouldOverridePackageLicense(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 PackageOverrideEntry - }{ - { - name: "Exact version entry exists", - config: Config{ - PackageOverrides: []PackageOverrideEntry{ - { - Name: "lib1", - Version: "1.0.0", - Ecosystem: "Go", - License: License{ - Override: []string{"mit"}, - }, - Reason: "abc", - }, - }, - }, - args: args{ - name: "lib1", - version: "1.0.0", - ecosystem: "Go", - }, - wantOk: true, - wantEntry: PackageOverrideEntry{ - Name: "lib1", - Version: "1.0.0", - Ecosystem: "Go", - License: License{ - Override: []string{"mit"}, - }, - Reason: "abc", - }, - }, - { - name: "Version entry doesn't exist", - config: Config{ - PackageOverrides: []PackageOverrideEntry{ - { - 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: PackageOverrideEntry{}, - }, - { - name: "Name matches", - config: Config{ - PackageOverrides: []PackageOverrideEntry{ - { - Name: "lib1", - Ecosystem: "Go", - License: License{ - Override: []string{"mit"}, - }, - Reason: "abc", - }, - }, - }, - args: args{ - name: "lib1", - version: "1.0.1", - ecosystem: "Go", - }, - wantOk: true, - wantEntry: PackageOverrideEntry{ - Name: "lib1", - Ecosystem: "Go", - License: License{ - Override: []string{"mit"}, - }, - Reason: "abc", - }, - }, - } - - for _, tt := range tests { - 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/internal/output/__snapshots__/sarif_test.snap b/internal/output/__snapshots__/sarif_test.snap index f306395f03..ec9062ba3e 100755 --- a/internal/output/__snapshots__/sarif_test.snap +++ b/internal/output/__snapshots__/sarif_test.snap @@ -62,7 +62,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -149,7 +149,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -170,7 +170,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -191,7 +191,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -212,7 +212,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -233,7 +233,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -254,7 +254,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -275,7 +275,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -296,7 +296,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -317,7 +317,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -338,7 +338,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -359,7 +359,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -380,7 +380,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -401,7 +401,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -422,7 +422,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -443,7 +443,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -501,7 +501,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -631,7 +631,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -743,7 +743,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -809,7 +809,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -875,7 +875,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -941,7 +941,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -1061,7 +1061,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -1272,7 +1272,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -1410,7 +1410,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -1468,7 +1468,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -1634,7 +1634,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -1845,7 +1845,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -1983,7 +1983,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -2004,7 +2004,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -2025,7 +2025,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -2046,7 +2046,7 @@ "informationUri": "https://github.com/google/osv-scanner", "name": "osv-scanner", "rules": [], - "version": "1.9.0" + "version": "1.9.1" } }, "results": [] @@ -2104,7 +2104,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -2187,7 +2187,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -2253,7 +2253,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -2319,7 +2319,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -2385,7 +2385,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -2452,7 +2452,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -2536,7 +2536,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -2637,7 +2637,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -2720,7 +2720,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ @@ -2786,7 +2786,7 @@ } } ], - "version": "1.9.0" + "version": "1.9.1" } }, "artifacts": [ diff --git a/internal/semantic/fixtures/alpine-versions.txt b/internal/semantic/fixtures/alpine-versions.txt index 22ed323d48..53bc7e3d2a 100644 --- a/internal/semantic/fixtures/alpine-versions.txt +++ b/internal/semantic/fixtures/alpine-versions.txt @@ -47,6 +47,14 @@ 1.2_svn1 > 1.2_csv2 1.2_cvs1 > 1.2_blah +# technically invalid, but "apk version -t" still accepts them +.1 < 1 +1 > .1 +.2 > .1 +a < b +c > b +c = c + # from https://raw.githubusercontent.com/alpinelinux/apk-tools/master/tests/version.data 2.34 > 0.1.0_alpha # todo: this might be invalid? diff --git a/internal/semantic/parse.go b/internal/semantic/parse.go index d555f2c1ab..b507ce806e 100644 --- a/internal/semantic/parse.go +++ b/internal/semantic/parse.go @@ -22,36 +22,36 @@ func MustParse(str string, ecosystem models.Ecosystem) Version { func Parse(str string, ecosystem models.Ecosystem) (Version, error) { //nolint:exhaustive // Using strings to specify ecosystem instead of lockfile types switch ecosystem { - case "npm": + case "Alpine": + return parseAlpineVersion(str), nil + case "ConanCenter": return parseSemverVersion(str), nil + case "CRAN": + return parseCRANVersion(str), nil case "crates.io": return parseSemverVersion(str), nil case "Debian": return parseDebianVersion(str), nil - case "Ubuntu": - return parseDebianVersion(str), nil - case "Alpine": - return parseAlpineVersion(str), nil - case "RubyGems": - return parseRubyGemsVersion(str), nil - case "NuGet": - return parseNuGetVersion(str), nil - case "Packagist": - return parsePackagistVersion(str), nil case "Go": return parseSemverVersion(str), nil case "Hex": return parseSemverVersion(str), nil case "Maven": return parseMavenVersion(str), nil - case "PyPI": - return parsePyPIVersion(str), nil - case "Pub": + case "npm": return parseSemverVersion(str), nil - case "ConanCenter": + case "NuGet": + return parseNuGetVersion(str), nil + case "Packagist": + return parsePackagistVersion(str), nil + case "Pub": return parseSemverVersion(str), nil - case "CRAN": - return parseCRANVersion(str), nil + case "PyPI": + return parsePyPIVersion(str), nil + case "RubyGems": + return parseRubyGemsVersion(str), nil + case "Ubuntu": + return parseDebianVersion(str), nil } return nil, fmt.Errorf("%w %s", ErrUnsupportedEcosystem, ecosystem) diff --git a/internal/semantic/parse_test.go b/internal/semantic/parse_test.go index 513af3d312..99f8083ce7 100644 --- a/internal/semantic/parse_test.go +++ b/internal/semantic/parse_test.go @@ -14,8 +14,7 @@ func TestParse(t *testing.T) { ecosystems := lockfile.KnownEcosystems() - // todo: remove once CRAN is supported by lockfile - ecosystems = append(ecosystems, "CRAN") + ecosystems = append(ecosystems, "Alpine", "Debian", "Ubuntu") for _, ecosystem := range ecosystems { _, err := semantic.Parse("", models.Ecosystem(ecosystem)) @@ -37,8 +36,7 @@ func TestMustParse(t *testing.T) { ecosystems := lockfile.KnownEcosystems() - // todo: remove once CRAN is supported by lockfile - ecosystems = append(ecosystems, "CRAN") + ecosystems = append(ecosystems, "Alpine", "Debian", "Ubuntu") for _, ecosystem := range ecosystems { semantic.MustParse("", models.Ecosystem(ecosystem)) diff --git a/internal/semantic/version-alpine.go b/internal/semantic/version-alpine.go index 722b989b4d..9030e51812 100644 --- a/internal/semantic/version-alpine.go +++ b/internal/semantic/version-alpine.go @@ -223,6 +223,10 @@ func (v AlpineVersion) CompareStr(str string) int { func parseAlpineNumberComponents(v *AlpineVersion, str string) string { sub := cachedregexp.MustCompile(`^((\d+)\.?)*`).FindString(str) + if sub == "" { + return str + } + for i, d := range strings.Split(sub, ".") { v.components = append(v.components, alpineNumberComponent{ value: convertToBigIntOrPanic(d), diff --git a/internal/semantic/version-pypi.go b/internal/semantic/version-pypi.go index ab3f1af76e..8363a1e3c4 100644 --- a/internal/semantic/version-pypi.go +++ b/internal/semantic/version-pypi.go @@ -184,16 +184,6 @@ func (pv PyPIVersion) compareRelease(pw PyPIVersion) int { return pv.release.Cmp(pw.release) } -func (pv PyPIVersion) preIndex() int { - for i, pre := range []string{"a", "b", "rc"} { - if pre == pv.pre.letter { - return i - } - } - - panic("unknown prefix " + pv.pre.letter) -} - // Checks if this PyPIVersion should apply a sort trick when comparing pre, // which ensures that i.e. 1.0.dev0 is before 1.0a0. func (pv PyPIVersion) shouldApplyPreTrick() bool { @@ -222,12 +212,8 @@ func (pv PyPIVersion) comparePre(pw PyPIVersion) int { case pw.pre.number == nil: return -1 default: - ai := pv.preIndex() - bi := pw.preIndex() - - if ai == bi { - return pv.pre.number.Cmp(pw.pre.number) - } + ai := pv.pre.letter[0] + bi := pw.pre.letter[0] if ai > bi { return +1 @@ -236,7 +222,7 @@ func (pv PyPIVersion) comparePre(pw PyPIVersion) int { return -1 } - return 0 + return pv.pre.number.Cmp(pw.pre.number) } } diff --git a/internal/semantic/version-rubygems.go b/internal/semantic/version-rubygems.go index d289fe5efd..2904d21193 100644 --- a/internal/semantic/version-rubygems.go +++ b/internal/semantic/version-rubygems.go @@ -1,7 +1,6 @@ package semantic import ( - "strconv" "strings" ) @@ -75,8 +74,6 @@ func canonicalSegments(segs []string) (canSegs []string) { func compareRubyGemsComponents(a, b []string) int { numberOfComponents := max(len(a), len(b)) - var compare int - for i := range numberOfComponents { as := fetch(a, i, "0") bs := fetch(b, i, "0") @@ -86,42 +83,18 @@ func compareRubyGemsComponents(a, b []string) int { switch { case aIsNumber && bIsNumber: - compare = ai.Cmp(bi) + if diff := ai.Cmp(bi); diff != 0 { + return diff + } case !aIsNumber && !bIsNumber: - compare = strings.Compare(as, bs) + if diff := strings.Compare(as, bs); diff != 0 { + return diff + } case aIsNumber: - compare = +1 + return +1 default: - compare = -1 - } - - if compare != 0 { - if compare > 0 { - return 1 - } - - return -1 - } - } - - if len(a) > len(b) { - next := a[len(b)] - - if _, err := strconv.Atoi(next); err == nil { - return 1 - } - - return -1 - } - - if len(a) < len(b) { - next := b[len(a)] - - if _, err := strconv.Atoi(next); err == nil { return -1 } - - return +1 } return 0 diff --git a/internal/semantic/version-semver-like.go b/internal/semantic/version-semver-like.go index fbb63bc689..3ccfe91846 100644 --- a/internal/semantic/version-semver-like.go +++ b/internal/semantic/version-semver-like.go @@ -38,10 +38,6 @@ func (v *SemverLikeVersion) fetchComponentsAndBuild(maxComponents int) (Componen func ParseSemverLikeVersion(line string, maxComponents int) SemverLikeVersion { v := parseSemverLike(line) - if maxComponents == -1 { - return v - } - components, build := v.fetchComponentsAndBuild(maxComponents) return SemverLikeVersion{ @@ -60,7 +56,6 @@ func parseSemverLike(line string) SemverLikeVersion { currentCom := "" foundBuild := false - emptyComponent := false leadingV := strings.HasPrefix(line, "v") line = strings.TrimPrefix(line, "v") @@ -94,15 +89,11 @@ func parseSemverLike(line string) SemverLikeVersion { components = append(components, v) currentCom = "" - - emptyComponent = false } // a component terminator means there might be another component // afterwards, so don't start parsing the build string just yet if c == '.' { - emptyComponent = true - continue } @@ -118,19 +109,6 @@ func parseSemverLike(line string) SemverLikeVersion { components = append(components, v) currentCom = "" - emptyComponent = false - } - - // if we ended with an empty component section, - // prefix the build string with a '.' - if emptyComponent { - currentCom = "." + currentCom - } - - // if we found no components, then the v wasn't actually leading - if len(components) == 0 && leadingV { - leadingV = false - currentCom = "v" + currentCom } return SemverLikeVersion{ diff --git a/internal/version/version.go b/internal/version/version.go index 23920c77e5..995b31d6ea 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -1,4 +1,4 @@ package version // OSVVersion is the current release version, you should update this variable when doing a release -var OSVVersion = "1.9.0" +var OSVVersion = "1.9.1" diff --git a/pkg/lockfile/fixtures/pnpm/invalid-package-path.yaml b/pkg/lockfile/fixtures/pnpm/invalid-package-path.yaml new file mode 100644 index 0000000000..099ce241e2 --- /dev/null +++ b/pkg/lockfile/fixtures/pnpm/invalid-package-path.yaml @@ -0,0 +1,92 @@ +lockfileVersion: 5.4 + +specifiers: + '@types/jsdom': ^20.0.1 + axios: ^1.2.5 + pinia: ^2.0.28 + stream: 0.0.2 + typescript: ~4.7.4 + +dependencies: + axios: 1.2.5 + pinia: 2.0.28_e7lp6ggkpgyi5vqd44m2kxvk6i + stream: 0.0.2 + +devDependencies: + '@types/jsdom': 20.0.1 + npm-run-all: 4.1.5 + +packages: + + /@babel/helper-string-parser/7.19.4: + resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-identifier/7.19.1: + resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} + engines: {node: '>=6.9.0'} + + /@babel/parser/7.20.7: + resolution: {integrity: sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.20.7 + + /@types/jsdom/20.0.1: + resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} + dependencies: + '@types/node': 18.11.18 + '@types/tough-cookie': 4.0.2 + parse5: 7.1.2 + dev: true + + axios@1.2.5: + resolution: {integrity: sha512-9pU/8mmjSSOb4CXVsvGIevN+MlO/t9OWtKadTaLuN85Gge3HGorUckgp8A/2FH4V4hJ7JuQ3LIeI7KAV9ITZrQ==} + dependencies: + follow-redirects: 1.15.2 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: false + + /stream/0.0.2: + resolution: {integrity: sha512-gCq3NDI2P35B2n6t76YJuOp7d6cN/C7Rt0577l91wllh0sY9ZBuw9KaSGqH/b0hzn3CWWJbpbW0W0WvQ1H/Q7g==} + dependencies: + emitter-component: 1.1.1 + dev: false + + /typescript/4.7.4: + resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==} + engines: {node: '>=4.2.0'} + hasBin: true + + /pinia/2.0.28_e7lp6ggkpgyi5vqd44m2kxvk6i: + resolution: {integrity: sha512-YClq9DkqCblq9rlyUual7ezMu/iICWdBtfJrDt4oWU9Zxpijyz7xB2xTwx57DaBQ96UGvvTMORzALr+iO5PVMw==} + peerDependencies: + '@vue/composition-api': ^1.4.0 + typescript: '>=4.4.4' + vue: ^2.6.14 || ^3.2.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + typescript: + optional: true + dependencies: + '@vue/devtools-api': 6.4.5 + typescript: 4.7.4 + vue: 3.2.45 + vue-demi: 0.13.11_vue@3.2.45 + dev: false + + /http-proxy-agent/5.0.0: + resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} + engines: {node: '>= 6'} + dependencies: + '@tootallnate/once': 2.0.0 + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true \ No newline at end of file diff --git a/pkg/lockfile/parse-pnpm-lock.go b/pkg/lockfile/parse-pnpm-lock.go index bb220706de..545450fa5d 100644 --- a/pkg/lockfile/parse-pnpm-lock.go +++ b/pkg/lockfile/parse-pnpm-lock.go @@ -65,12 +65,12 @@ func startsWithNumber(str string) bool { // extractPnpmPackageNameAndVersion parses a dependency path, attempting to // extract the name and version of the package it represents -func extractPnpmPackageNameAndVersion(dependencyPath string, lockfileVersion float64) (string, string) { +func extractPnpmPackageNameAndVersion(dependencyPath string, lockfileVersion float64) (string, string, error) { // file dependencies must always have a name property to be installed, // and their dependency path never has the version encoded, so we can // skip trying to extract either from their dependency path if strings.HasPrefix(dependencyPath, "file:") { - return "", "" + return "", "", nil } // v9.0 specifies the dependencies as @ rather than as a path @@ -84,10 +84,15 @@ func extractPnpmPackageNameAndVersion(dependencyPath string, lockfileVersion flo name = "@" + name } - return name, version + return name, version, nil } parts := strings.Split(dependencyPath, "/") + + if len(parts) == 1 { + return "", "", errors.New("invalid package path") + } + var name string parts = parts[1:] @@ -111,7 +116,7 @@ func extractPnpmPackageNameAndVersion(dependencyPath string, lockfileVersion flo } if version == "" || !startsWithNumber(version) { - return "", "" + return "", "", nil } underscoreIndex := strings.Index(version, "_") @@ -120,7 +125,7 @@ func extractPnpmPackageNameAndVersion(dependencyPath string, lockfileVersion flo version = strings.Split(version, "_")[0] } - return name, version + return name, version, nil } func parseNameAtVersion(value string) (name string, version string) { @@ -134,11 +139,15 @@ func parseNameAtVersion(value string) (name string, version string) { return matches[1], matches[2] } -func parsePnpmLock(lockfile PnpmLockfile) []PackageDetails { +func parsePnpmLock(lockfile PnpmLockfile) ([]PackageDetails, error) { packages := make([]PackageDetails, 0, len(lockfile.Packages)) for s, pkg := range lockfile.Packages { - name, version := extractPnpmPackageNameAndVersion(s, lockfile.Version) + name, version, err := extractPnpmPackageNameAndVersion(s, lockfile.Version) + + if err != nil { + return nil, err + } // "name" is only present if it's not in the dependency path and takes // priority over whatever name we think we've extracted (if any) @@ -182,7 +191,7 @@ func parsePnpmLock(lockfile PnpmLockfile) []PackageDetails { }) } - return packages + return packages, nil } type PnpmLockExtractor struct{} @@ -205,7 +214,12 @@ func (e PnpmLockExtractor) Extract(f DepFile) ([]PackageDetails, error) { parsedLockfile = &PnpmLockfile{} } - return parsePnpmLock(*parsedLockfile), nil + packageDetails, err := parsePnpmLock(*parsedLockfile) + if err != nil { + return []PackageDetails{}, fmt.Errorf("could not extract from %s: %w", f.Path(), err) + } + + return packageDetails, nil } var _ Extractor = PnpmLockExtractor{} diff --git a/pkg/lockfile/parse-pnpm-lock_test.go b/pkg/lockfile/parse-pnpm-lock_test.go index a08c11596f..bee7c6b4aa 100644 --- a/pkg/lockfile/parse-pnpm-lock_test.go +++ b/pkg/lockfile/parse-pnpm-lock_test.go @@ -586,3 +586,12 @@ func TestParsePnpmLock_Files(t *testing.T) { }, }) } + +func TestParsePnpmLock_InvalidPackagePath(t *testing.T) { + t.Parallel() + + packages, err := lockfile.ParsePnpmLock("fixtures/pnpm/invalid-package-path.yaml") + + expectErrContaining(t, err, "invalid package path") + expectPackages(t, packages, []lockfile.PackageDetails{}) +} diff --git a/pkg/osvscanner/osvscanner.go b/pkg/osvscanner/osvscanner.go index 9e74a64739..e04b01b8d9 100644 --- a/pkg/osvscanner/osvscanner.go +++ b/pkg/osvscanner/osvscanner.go @@ -739,7 +739,7 @@ func scanDockerImage(r reporter.Reporter, dockerImageName string) ([]scannedPack } // Filters results according to config, preserving order. Returns total number of vulnerabilities removed. -func filterResults(r reporter.Reporter, results *models.VulnerabilityResults, configManager *config.ConfigManager, allPackages bool) int { +func filterResults(r reporter.Reporter, results *models.VulnerabilityResults, configManager *config.Manager, allPackages bool) int { removedCount := 0 unimportantCount := 0 newResults := []models.PackageSource{} // Want 0 vulnerabilities to show in JSON as an empty list, not null. @@ -893,7 +893,7 @@ func DoScan(actions ScannerActions, r reporter.Reporter) (models.VulnerabilityRe return models.VulnerabilityResults{}, errors.New("databases can only be downloaded when running in offline mode") } - configManager := config.ConfigManager{ + configManager := config.Manager{ DefaultConfig: config.Config{}, ConfigMap: make(map[string]config.Config), } @@ -1059,7 +1059,7 @@ func filterUnscannablePackages(packages []scannedPackage) []scannedPackage { } // filterIgnoredPackages removes ignore scanned packages according to config. Returns filtered scanned packages. -func filterIgnoredPackages(r reporter.Reporter, packages []scannedPackage, configManager *config.ConfigManager) []scannedPackage { +func filterIgnoredPackages(r reporter.Reporter, packages []scannedPackage, configManager *config.Manager) []scannedPackage { out := make([]scannedPackage, 0, len(packages)) for _, p := range packages { configToUse := configManager.Get(r, p.Source.Path) @@ -1193,7 +1193,7 @@ func makeLicensesRequests(packages []scannedPackage) ([][]models.License, error) } // Overrides Go version using osv-scanner.toml -func overrideGoVersion(r reporter.Reporter, packages []scannedPackage, configManager *config.ConfigManager) { +func overrideGoVersion(r reporter.Reporter, packages []scannedPackage, configManager *config.Manager) { for i, pkg := range packages { if pkg.Name == "stdlib" && pkg.Ecosystem == "Go" { configToUse := configManager.Get(r, pkg.Source.Path) diff --git a/pkg/osvscanner/osvscanner_internal_test.go b/pkg/osvscanner/osvscanner_internal_test.go index 8b53753e2d..ec2e5b071c 100644 --- a/pkg/osvscanner/osvscanner_internal_test.go +++ b/pkg/osvscanner/osvscanner_internal_test.go @@ -40,9 +40,9 @@ func Test_filterResults(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() r := &reporter.VoidReporter{} - // ConfigManager looks for osv-scanner.toml in the source path. + // configManager looks for osv-scanner.toml in the source path. // Sources in the test input should point to files/folders in the text fixture folder for this to work correctly. - configManager := config.ConfigManager{ + configManager := config.Manager{ DefaultConfig: config.Config{}, ConfigMap: make(map[string]config.Config), } diff --git a/pkg/osvscanner/vulnerability_result.go b/pkg/osvscanner/vulnerability_result.go index aa837ebb66..298488763e 100644 --- a/pkg/osvscanner/vulnerability_result.go +++ b/pkg/osvscanner/vulnerability_result.go @@ -24,7 +24,7 @@ func buildVulnerabilityResults( vulnsResp *osv.HydratedBatchedResponse, licensesResp [][]models.License, actions ScannerActions, - configManager *config.ConfigManager, + configManager *config.Manager, ) models.VulnerabilityResults { results := models.VulnerabilityResults{ Results: []models.PackageSource{}, diff --git a/pkg/osvscanner/vulnerability_result_internal_test.go b/pkg/osvscanner/vulnerability_result_internal_test.go index 7b1bcfa65f..c60d8503a6 100644 --- a/pkg/osvscanner/vulnerability_result_internal_test.go +++ b/pkg/osvscanner/vulnerability_result_internal_test.go @@ -19,7 +19,7 @@ func Test_assembleResult(t *testing.T) { vulnsResp *osv.HydratedBatchedResponse licensesResp [][]models.License actions ScannerActions - config *config.ConfigManager + config *config.Manager } packages := []scannedPackage{ { @@ -99,7 +99,7 @@ func Test_assembleResult(t *testing.T) { }, CallAnalysisStates: callAnalysisStates, }, - config: &config.ConfigManager{}, + config: &config.Manager{}, }, }, { name: "group_vulnerabilities_with_all_packages_included", @@ -115,7 +115,7 @@ func Test_assembleResult(t *testing.T) { }, CallAnalysisStates: callAnalysisStates, }, - config: &config.ConfigManager{}, + config: &config.Manager{}, }, }, { name: "group_vulnerabilities_with_licenses", @@ -132,7 +132,7 @@ func Test_assembleResult(t *testing.T) { }, CallAnalysisStates: callAnalysisStates, }, - config: &config.ConfigManager{}, + config: &config.Manager{}, }, }, { name: "group_vulnerabilities_with_license_allowlist", @@ -149,7 +149,7 @@ func Test_assembleResult(t *testing.T) { CallAnalysisStates: callAnalysisStates, }, - config: &config.ConfigManager{}, + config: &config.Manager{}, }, }, { name: "group_vulnerabilities_with_license_allowlist_and_license_override", @@ -165,7 +165,7 @@ func Test_assembleResult(t *testing.T) { }, CallAnalysisStates: callAnalysisStates, }, - config: &config.ConfigManager{ + config: &config.Manager{ OverrideConfig: &config.Config{ PackageOverrides: []config.PackageOverrideEntry{ { @@ -193,7 +193,7 @@ func Test_assembleResult(t *testing.T) { }, CallAnalysisStates: callAnalysisStates, }, - config: &config.ConfigManager{}, + config: &config.Manager{}, }, }} for _, tt := range tests {