From ded5a87ea2038a1d1b64e0de779a456918d56eae Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Fri, 24 Jan 2025 14:14:47 -0500 Subject: [PATCH] remove v3 and v4 schema usage (#482) Signed-off-by: Alex Goodman --- .../grype_db_manager/data/schema-info.json | 4 +- manager/tests/unit/db/test_schema.py | 2 +- pkg/process/build.go | 12 - pkg/process/v3/processors.go | 19 - pkg/process/v3/transformers/entry.go | 22 - .../test-fixtures/github-github-npm-0.json | 31 - .../test-fixtures/github-github-python-0.json | 58 -- .../test-fixtures/github-github-python-1.json | 43 - .../test-fixtures/github-withdrawn.json | 29 - .../multiple-fixed-in-names.json | 43 - .../v3/transformers/github/transform.go | 99 --- .../v3/transformers/github/transform_test.go | 198 ----- .../msrc/test-fixtures/microsoft-msrc-0.json | 194 ----- pkg/process/v3/transformers/msrc/transform.go | 91 --- .../v3/transformers/msrc/transform_test.go | 120 --- .../nvd/test-fixtures/compound-pkg.json | 115 --- .../nvd/test-fixtures/invalid_cpe.json | 111 --- .../single-package-multi-distro.json | 174 ---- .../nvd/test-fixtures/unmarshal-test.json | 109 --- .../nvd/test-fixtures/version-range.json | 121 --- pkg/process/v3/transformers/nvd/transform.go | 95 --- .../v3/transformers/nvd/transform_test.go | 257 ------ pkg/process/v3/transformers/nvd/unique_pkg.go | 115 --- .../v3/transformers/nvd/unique_pkg_test.go | 353 -------- .../v3/transformers/nvd/unique_pkg_tracker.go | 64 -- .../os/test-fixtures/alpine-3.9.json | 28 - .../amazon-multiple-kernel-advisories.json | 104 --- .../transformers/os/test-fixtures/amzn.json | 49 -- ...n-8-multiple-entries-for-same-package.json | 62 -- .../os/test-fixtures/debian-8.json | 62 -- .../os/test-fixtures/ol-8-modules.json | 36 - .../transformers/os/test-fixtures/ol-8.json | 42 - .../os/test-fixtures/rhel-8-modules.json | 75 -- .../transformers/os/test-fixtures/rhel-8.json | 57 -- .../os/test-fixtures/unmarshal-test.json | 104 --- pkg/process/v3/transformers/os/transform.go | 182 ----- .../v3/transformers/os/transform_test.go | 758 ------------------ .../v3/transformers/vulnerability_metadata.go | 8 - pkg/process/v3/writer.go | 132 --- pkg/process/v3/writer_test.go | 126 --- pkg/process/v4/processors.go | 21 - pkg/process/v4/transformers/entry.go | 22 - .../test-fixtures/github-github-npm-0.json | 31 - .../test-fixtures/github-github-python-0.json | 58 -- .../test-fixtures/github-github-python-1.json | 43 - .../test-fixtures/github-withdrawn.json | 29 - .../multiple-fixed-in-names.json | 43 - .../v4/transformers/github/transform.go | 138 ---- .../v4/transformers/github/transform_test.go | 255 ------ .../transformers/matchexclusions/transform.go | 42 - .../msrc/test-fixtures/microsoft-msrc-0.json | 194 ----- pkg/process/v4/transformers/msrc/transform.go | 114 --- .../v4/transformers/msrc/transform_test.go | 120 --- .../nvd/test-fixtures/compound-pkg.json | 115 --- .../nvd/test-fixtures/invalid_cpe.json | 111 --- .../single-package-multi-distro.json | 174 ---- .../nvd/test-fixtures/unmarshal-test.json | 109 --- .../nvd/test-fixtures/version-range.json | 121 --- pkg/process/v4/transformers/nvd/transform.go | 109 --- .../v4/transformers/nvd/transform_test.go | 257 ------ pkg/process/v4/transformers/nvd/unique_pkg.go | 115 --- .../v4/transformers/nvd/unique_pkg_test.go | 353 -------- .../v4/transformers/nvd/unique_pkg_tracker.go | 64 -- .../os/test-fixtures/alpine-3.9.json | 28 - .../amazon-multiple-kernel-advisories.json | 104 --- .../transformers/os/test-fixtures/amzn.json | 49 -- ...n-8-multiple-entries-for-same-package.json | 62 -- .../os/test-fixtures/debian-8.json | 62 -- .../os/test-fixtures/ol-8-modules.json | 36 - .../transformers/os/test-fixtures/ol-8.json | 42 - .../os/test-fixtures/rhel-8-modules.json | 75 -- .../transformers/os/test-fixtures/rhel-8.json | 57 -- .../os/test-fixtures/unmarshal-test.json | 104 --- pkg/process/v4/transformers/os/transform.go | 218 ----- .../v4/transformers/os/transform_test.go | 757 ----------------- .../v4/transformers/vulnerability_metadata.go | 8 - pkg/process/v4/writer.go | 142 ---- pkg/process/v4/writer_test.go | 126 --- 78 files changed, 3 insertions(+), 8809 deletions(-) delete mode 100644 pkg/process/v3/processors.go delete mode 100644 pkg/process/v3/transformers/entry.go delete mode 100644 pkg/process/v3/transformers/github/test-fixtures/github-github-npm-0.json delete mode 100644 pkg/process/v3/transformers/github/test-fixtures/github-github-python-0.json delete mode 100644 pkg/process/v3/transformers/github/test-fixtures/github-github-python-1.json delete mode 100644 pkg/process/v3/transformers/github/test-fixtures/github-withdrawn.json delete mode 100644 pkg/process/v3/transformers/github/test-fixtures/multiple-fixed-in-names.json delete mode 100644 pkg/process/v3/transformers/github/transform.go delete mode 100644 pkg/process/v3/transformers/github/transform_test.go delete mode 100644 pkg/process/v3/transformers/msrc/test-fixtures/microsoft-msrc-0.json delete mode 100644 pkg/process/v3/transformers/msrc/transform.go delete mode 100644 pkg/process/v3/transformers/msrc/transform_test.go delete mode 100644 pkg/process/v3/transformers/nvd/test-fixtures/compound-pkg.json delete mode 100644 pkg/process/v3/transformers/nvd/test-fixtures/invalid_cpe.json delete mode 100644 pkg/process/v3/transformers/nvd/test-fixtures/single-package-multi-distro.json delete mode 100644 pkg/process/v3/transformers/nvd/test-fixtures/unmarshal-test.json delete mode 100644 pkg/process/v3/transformers/nvd/test-fixtures/version-range.json delete mode 100644 pkg/process/v3/transformers/nvd/transform.go delete mode 100644 pkg/process/v3/transformers/nvd/transform_test.go delete mode 100644 pkg/process/v3/transformers/nvd/unique_pkg.go delete mode 100644 pkg/process/v3/transformers/nvd/unique_pkg_test.go delete mode 100644 pkg/process/v3/transformers/nvd/unique_pkg_tracker.go delete mode 100644 pkg/process/v3/transformers/os/test-fixtures/alpine-3.9.json delete mode 100644 pkg/process/v3/transformers/os/test-fixtures/amazon-multiple-kernel-advisories.json delete mode 100644 pkg/process/v3/transformers/os/test-fixtures/amzn.json delete mode 100644 pkg/process/v3/transformers/os/test-fixtures/debian-8-multiple-entries-for-same-package.json delete mode 100644 pkg/process/v3/transformers/os/test-fixtures/debian-8.json delete mode 100644 pkg/process/v3/transformers/os/test-fixtures/ol-8-modules.json delete mode 100644 pkg/process/v3/transformers/os/test-fixtures/ol-8.json delete mode 100644 pkg/process/v3/transformers/os/test-fixtures/rhel-8-modules.json delete mode 100644 pkg/process/v3/transformers/os/test-fixtures/rhel-8.json delete mode 100644 pkg/process/v3/transformers/os/test-fixtures/unmarshal-test.json delete mode 100644 pkg/process/v3/transformers/os/transform.go delete mode 100644 pkg/process/v3/transformers/os/transform_test.go delete mode 100644 pkg/process/v3/transformers/vulnerability_metadata.go delete mode 100644 pkg/process/v3/writer.go delete mode 100644 pkg/process/v3/writer_test.go delete mode 100644 pkg/process/v4/processors.go delete mode 100644 pkg/process/v4/transformers/entry.go delete mode 100644 pkg/process/v4/transformers/github/test-fixtures/github-github-npm-0.json delete mode 100644 pkg/process/v4/transformers/github/test-fixtures/github-github-python-0.json delete mode 100644 pkg/process/v4/transformers/github/test-fixtures/github-github-python-1.json delete mode 100644 pkg/process/v4/transformers/github/test-fixtures/github-withdrawn.json delete mode 100644 pkg/process/v4/transformers/github/test-fixtures/multiple-fixed-in-names.json delete mode 100644 pkg/process/v4/transformers/github/transform.go delete mode 100644 pkg/process/v4/transformers/github/transform_test.go delete mode 100644 pkg/process/v4/transformers/matchexclusions/transform.go delete mode 100644 pkg/process/v4/transformers/msrc/test-fixtures/microsoft-msrc-0.json delete mode 100644 pkg/process/v4/transformers/msrc/transform.go delete mode 100644 pkg/process/v4/transformers/msrc/transform_test.go delete mode 100644 pkg/process/v4/transformers/nvd/test-fixtures/compound-pkg.json delete mode 100644 pkg/process/v4/transformers/nvd/test-fixtures/invalid_cpe.json delete mode 100644 pkg/process/v4/transformers/nvd/test-fixtures/single-package-multi-distro.json delete mode 100644 pkg/process/v4/transformers/nvd/test-fixtures/unmarshal-test.json delete mode 100644 pkg/process/v4/transformers/nvd/test-fixtures/version-range.json delete mode 100644 pkg/process/v4/transformers/nvd/transform.go delete mode 100644 pkg/process/v4/transformers/nvd/transform_test.go delete mode 100644 pkg/process/v4/transformers/nvd/unique_pkg.go delete mode 100644 pkg/process/v4/transformers/nvd/unique_pkg_test.go delete mode 100644 pkg/process/v4/transformers/nvd/unique_pkg_tracker.go delete mode 100644 pkg/process/v4/transformers/os/test-fixtures/alpine-3.9.json delete mode 100644 pkg/process/v4/transformers/os/test-fixtures/amazon-multiple-kernel-advisories.json delete mode 100644 pkg/process/v4/transformers/os/test-fixtures/amzn.json delete mode 100644 pkg/process/v4/transformers/os/test-fixtures/debian-8-multiple-entries-for-same-package.json delete mode 100644 pkg/process/v4/transformers/os/test-fixtures/debian-8.json delete mode 100644 pkg/process/v4/transformers/os/test-fixtures/ol-8-modules.json delete mode 100644 pkg/process/v4/transformers/os/test-fixtures/ol-8.json delete mode 100644 pkg/process/v4/transformers/os/test-fixtures/rhel-8-modules.json delete mode 100644 pkg/process/v4/transformers/os/test-fixtures/rhel-8.json delete mode 100644 pkg/process/v4/transformers/os/test-fixtures/unmarshal-test.json delete mode 100644 pkg/process/v4/transformers/os/transform.go delete mode 100644 pkg/process/v4/transformers/os/transform_test.go delete mode 100644 pkg/process/v4/transformers/vulnerability_metadata.go delete mode 100644 pkg/process/v4/writer.go delete mode 100644 pkg/process/v4/writer_test.go diff --git a/manager/src/grype_db_manager/data/schema-info.json b/manager/src/grype_db_manager/data/schema-info.json index 79131f2f..8e715236 100644 --- a/manager/src/grype_db_manager/data/schema-info.json +++ b/manager/src/grype_db_manager/data/schema-info.json @@ -13,12 +13,12 @@ { "schema": "3", "grype-version": "v0.40.1", - "supported": true + "supported": false }, { "schema": "4", "grype-version": "v0.50.2", - "supported": true + "supported": false }, { "schema": "5", diff --git a/manager/tests/unit/db/test_schema.py b/manager/tests/unit/db/test_schema.py index 2863efe3..7afc88b7 100644 --- a/manager/tests/unit/db/test_schema.py +++ b/manager/tests/unit/db/test_schema.py @@ -14,4 +14,4 @@ def test_grype_version(): def test_supported_schema_versions(): - assert schema.supported_schema_versions() == [3, 4, 5, 6] + assert schema.supported_schema_versions() == [5, 6] diff --git a/pkg/process/build.go b/pkg/process/build.go index 00fd73f9..f5455c4d 100644 --- a/pkg/process/build.go +++ b/pkg/process/build.go @@ -9,15 +9,11 @@ import ( "github.com/anchore/grype-db/internal/log" "github.com/anchore/grype-db/pkg/data" - v3 "github.com/anchore/grype-db/pkg/process/v3" - v4 "github.com/anchore/grype-db/pkg/process/v4" v5 "github.com/anchore/grype-db/pkg/process/v5" v6 "github.com/anchore/grype-db/pkg/process/v6" "github.com/anchore/grype-db/pkg/provider" "github.com/anchore/grype-db/pkg/provider/entry" "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDBv3 "github.com/anchore/grype/grype/db/v3" - grypeDBv4 "github.com/anchore/grype/grype/db/v4" grypeDBv5 "github.com/anchore/grype/grype/db/v5" grypeDBv6 "github.com/anchore/grype/grype/db/v6" ) @@ -76,10 +72,6 @@ type providerResults struct { func getProcessors(cfg BuildConfig) ([]data.Processor, error) { switch cfg.SchemaVersion { - case grypeDBv3.SchemaVersion: - return v3.Processors(), nil - case grypeDBv4.SchemaVersion: - return v4.Processors(), nil case grypeDBv5.SchemaVersion: return v5.Processors(v5.NewConfig(v5.WithCPEParts(cfg.IncludeCPEParts), v5.WithInferNVDFixVersions(cfg.InferNVDFixVersions))), nil case grypeDBv6.ModelVersion: @@ -91,10 +83,6 @@ func getProcessors(cfg BuildConfig) ([]data.Processor, error) { func getWriter(schemaVersion int, dataAge time.Time, directory string, states provider.States) (data.Writer, error) { switch schemaVersion { - case grypeDBv3.SchemaVersion: - return v3.NewWriter(directory, dataAge) - case grypeDBv4.SchemaVersion: - return v4.NewWriter(directory, dataAge) case grypeDBv5.SchemaVersion: return v5.NewWriter(directory, dataAge, states) case grypeDBv6.ModelVersion: diff --git a/pkg/process/v3/processors.go b/pkg/process/v3/processors.go deleted file mode 100644 index e7d51f4e..00000000 --- a/pkg/process/v3/processors.go +++ /dev/null @@ -1,19 +0,0 @@ -package v3 - -import ( - "github.com/anchore/grype-db/pkg/data" - "github.com/anchore/grype-db/pkg/process/processors" - "github.com/anchore/grype-db/pkg/process/v3/transformers/github" - "github.com/anchore/grype-db/pkg/process/v3/transformers/msrc" - "github.com/anchore/grype-db/pkg/process/v3/transformers/nvd" - "github.com/anchore/grype-db/pkg/process/v3/transformers/os" -) - -func Processors() []data.Processor { - return []data.Processor{ - processors.NewGitHubProcessor(github.Transform), - processors.NewMSRCProcessor(msrc.Transform), - processors.NewNVDProcessor(nvd.Transform), - processors.NewOSProcessor(os.Transform), - } -} diff --git a/pkg/process/v3/transformers/entry.go b/pkg/process/v3/transformers/entry.go deleted file mode 100644 index ae8f3715..00000000 --- a/pkg/process/v3/transformers/entry.go +++ /dev/null @@ -1,22 +0,0 @@ -package transformers - -import ( - "github.com/anchore/grype-db/pkg/data" - grypeDB "github.com/anchore/grype/grype/db/v3" -) - -func NewEntries(vs []grypeDB.Vulnerability, metadata grypeDB.VulnerabilityMetadata) []data.Entry { - entries := []data.Entry{ - { - DBSchemaVersion: grypeDB.SchemaVersion, - Data: metadata, - }, - } - for _, vuln := range vs { - entries = append(entries, data.Entry{ - DBSchemaVersion: grypeDB.SchemaVersion, - Data: vuln, - }) - } - return entries -} diff --git a/pkg/process/v3/transformers/github/test-fixtures/github-github-npm-0.json b/pkg/process/v3/transformers/github/test-fixtures/github-github-npm-0.json deleted file mode 100644 index b0a7d1e9..00000000 --- a/pkg/process/v3/transformers/github/test-fixtures/github-github-npm-0.json +++ /dev/null @@ -1,31 +0,0 @@ - -{ - "Advisory": { - "CVE": [ - "CVE-2020-14000" - ], - "FixedIn": [ - { - "ecosystem": "npm", - "identifier": "0.2.0-prerelease.20200714185213", - "name": "scratch-vm", - "namespace": "github:npm", - "range": "<= 0.2.0-prerelease.20200709173451" - } - ], - "Metadata": { - "CVE": [ - "CVE-2020-14000" - ] - }, - "Severity": "High", - "Summary": "Remote Code Execution in scratch-vm", - "ghsaId": "GHSA-vc9j-fhvv-8vrf", - "namespace": "github:npm", - "url": "https://github.com/advisories/GHSA-vc9j-fhvv-8vrf", - "withdrawn": null - }, - "Vulnerability": {} -} - - diff --git a/pkg/process/v3/transformers/github/test-fixtures/github-github-python-0.json b/pkg/process/v3/transformers/github/test-fixtures/github-github-python-0.json deleted file mode 100644 index ad14aa60..00000000 --- a/pkg/process/v3/transformers/github/test-fixtures/github-github-python-0.json +++ /dev/null @@ -1,58 +0,0 @@ -[ - { - "Advisory": { - "CVE": [ - "CVE-2018-8768" - ], - "FixedIn": [ - { - "ecosystem": "python", - "identifier": "5.4.1", - "name": "notebook", - "namespace": "github:python", - "range": "< 5.4.1" - } - ], - "Metadata": { - "CVE": [ - "CVE-2018-8768" - ] - }, - "Severity": "Low", - "Summary": "Low severity vulnerability that affects notebook", - "ghsaId": "GHSA-6cwv-x26c-w2q4", - "namespace": "github:python", - "url": "https://github.com/advisories/GHSA-6cwv-x26c-w2q4", - "withdrawn": null - }, - "Vulnerability": {} - }, - { - "Advisory": { - "CVE": [ - "CVE-2017-5524" - ], - "FixedIn": [ - { - "ecosystem": "python", - "identifier": "4.3.12", - "name": "Plone", - "namespace": "github:python", - "range": ">= 4.0 < 4.3.12" - } - ], - "Metadata": { - "CVE": [ - "CVE-2017-5524" - ] - }, - "Severity": "Medium", - "Summary": "Moderate severity vulnerability that affects Plone", - "ghsaId": "GHSA-p5wr-vp8g-q5p4", - "namespace": "github:python", - "url": "https://github.com/advisories/GHSA-p5wr-vp8g-q5p4", - "withdrawn": null - }, - "Vulnerability": {} - } -] \ No newline at end of file diff --git a/pkg/process/v3/transformers/github/test-fixtures/github-github-python-1.json b/pkg/process/v3/transformers/github/test-fixtures/github-github-python-1.json deleted file mode 100644 index bfa84922..00000000 --- a/pkg/process/v3/transformers/github/test-fixtures/github-github-python-1.json +++ /dev/null @@ -1,43 +0,0 @@ - -{ - "Advisory": { - "CVE": [ - "CVE-2017-5524" - ], - "FixedIn": [ - { - "ecosystem": "python", - "identifier": "4.3.12", - "name": "Plone", - "namespace": "github:python", - "range": ">= 4.0 < 4.3.12" - }, - { - "ecosystem": "python", - "identifier": "5.1b1", - "name": "Plone", - "namespace": "github:python", - "range": ">= 5.1a1 < 5.1b1" - }, - { - "ecosystem": "python", - "identifier": "5.0.7", - "name": "Plone", - "namespace": "github:python", - "range": ">= 5.0rc1 < 5.0.7" - } - ], - "Metadata": { - "CVE": [ - "CVE-2017-5524" - ] - }, - "Severity": "Medium", - "Summary": "Moderate severity vulnerability that affects Plone", - "ghsaId": "GHSA-p5wr-vp8g-q5p4", - "namespace": "github:python", - "url": "https://github.com/advisories/GHSA-p5wr-vp8g-q5p4", - "withdrawn": null - }, - "Vulnerability": {} -} diff --git a/pkg/process/v3/transformers/github/test-fixtures/github-withdrawn.json b/pkg/process/v3/transformers/github/test-fixtures/github-withdrawn.json deleted file mode 100644 index 04995e38..00000000 --- a/pkg/process/v3/transformers/github/test-fixtures/github-withdrawn.json +++ /dev/null @@ -1,29 +0,0 @@ - -{ - "Advisory": { - "CVE": [ - "CVE-2018-8768" - ], - "FixedIn": [ - { - "ecosystem": "python", - "identifier": "5.4.1", - "name": "notebook", - "namespace": "github:python", - "range": "< 5.4.1" - } - ], - "Metadata": { - "CVE": [ - "CVE-2018-8768" - ] - }, - "Severity": "Low", - "Summary": "Low severity vulnerability that affects notebook", - "ghsaId": "GHSA-6cwv-x26c-w2q4", - "namespace": "github:python", - "url": "https://github.com/advisories/GHSA-6cwv-x26c-w2q4", - "withdrawn": "2022-01-31T14:32:09Z" - }, - "Vulnerability": {} -} diff --git a/pkg/process/v3/transformers/github/test-fixtures/multiple-fixed-in-names.json b/pkg/process/v3/transformers/github/test-fixtures/multiple-fixed-in-names.json deleted file mode 100644 index ac1ef982..00000000 --- a/pkg/process/v3/transformers/github/test-fixtures/multiple-fixed-in-names.json +++ /dev/null @@ -1,43 +0,0 @@ - -{ - "Advisory": { - "CVE": [ - "CVE-2017-5524" - ], - "FixedIn": [ - { - "ecosystem": "python", - "identifier": "4.3.12", - "name": "Plone", - "namespace": "github:python", - "range": ">= 4.0 < 4.3.12" - }, - { - "ecosystem": "python", - "identifier": "5.1b1", - "name": "Plone", - "namespace": "github:python", - "range": ">= 5.1a1 < 5.1b1" - }, - { - "ecosystem": "python", - "identifier": "5.0.7", - "name": "Plone-debug", - "namespace": "github:python", - "range": ">= 5.0rc1 < 5.0.7" - } - ], - "Metadata": { - "CVE": [ - "CVE-2017-5524" - ] - }, - "Severity": "Medium", - "Summary": "Moderate severity vulnerability that affects Plone", - "ghsaId": "GHSA-p5wr-vp8g-q5p4", - "namespace": "github:python", - "url": "https://github.com/advisories/GHSA-p5wr-vp8g-q5p4", - "withdrawn": null - }, - "Vulnerability": {} -} diff --git a/pkg/process/v3/transformers/github/transform.go b/pkg/process/v3/transformers/github/transform.go deleted file mode 100644 index 882e8ee7..00000000 --- a/pkg/process/v3/transformers/github/transform.go +++ /dev/null @@ -1,99 +0,0 @@ -package github - -import ( - "github.com/anchore/grype-db/pkg/data" - "github.com/anchore/grype-db/pkg/process/internal/common" - "github.com/anchore/grype-db/pkg/process/v3/transformers" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v3" -) - -const ( - // TODO: tech debt from a previous design - feed = "github" -) - -func Transform(vulnerability unmarshal.GitHubAdvisory) ([]data.Entry, error) { - var allVulns []grypeDB.Vulnerability - - // Exclude entries marked as withdrawn - if vulnerability.Advisory.Withdrawn != "" { - return nil, nil - } - - recordSource := grypeDB.RecordSource(feed, vulnerability.Advisory.Namespace) - entryNamespace, err := grypeDB.NamespaceForFeedGroup(feed, vulnerability.Advisory.Namespace) - if err != nil { - return nil, err - } - - // there may be multiple packages indicated within the FixedIn field, we should make - // separate vulnerability entries (one for each name|namespaces combo) while merging - // constraint ranges as they are found. - for idx, fixedInEntry := range vulnerability.Advisory.FixedIn { - constraint := common.EnforceSemVerConstraint(fixedInEntry.Range) - - var versionFormat string - switch vulnerability.Advisory.Namespace { - case "github:python": - versionFormat = "python" - default: - versionFormat = "unknown" - } - - // create vulnerability entry - allVulns = append(allVulns, grypeDB.Vulnerability{ - ID: vulnerability.Advisory.GhsaID, - VersionConstraint: constraint, - VersionFormat: versionFormat, - RelatedVulnerabilities: getRelatedVulnerabilities(vulnerability), - PackageName: fixedInEntry.Name, - Namespace: entryNamespace, - Fix: getFix(vulnerability, idx), - }) - } - - // create vulnerability metadata entry (a single entry keyed off of the vulnerability ID) - metadata := grypeDB.VulnerabilityMetadata{ - ID: vulnerability.Advisory.GhsaID, - DataSource: vulnerability.Advisory.URL, - Namespace: entryNamespace, - RecordSource: recordSource, - Severity: vulnerability.Advisory.Severity, - URLs: []string{vulnerability.Advisory.URL}, - Description: vulnerability.Advisory.Summary, - } - - return transformers.NewEntries(allVulns, metadata), nil -} - -func getFix(entry unmarshal.GitHubAdvisory, idx int) grypeDB.Fix { - fixedInEntry := entry.Advisory.FixedIn[idx] - - var fixedInVersions []string - fixedInVersion := common.CleanFixedInVersion(fixedInEntry.Identifier) - if fixedInVersion != "" { - fixedInVersions = append(fixedInVersions, fixedInVersion) - } - - fixState := grypeDB.NotFixedState - if len(fixedInVersions) > 0 { - fixState = grypeDB.FixedState - } - - return grypeDB.Fix{ - Versions: fixedInVersions, - State: fixState, - } -} - -func getRelatedVulnerabilities(entry unmarshal.GitHubAdvisory) []grypeDB.VulnerabilityReference { - vulns := make([]grypeDB.VulnerabilityReference, len(entry.Advisory.CVE)) - for idx, cve := range entry.Advisory.CVE { - vulns[idx] = grypeDB.VulnerabilityReference{ - ID: cve, - Namespace: grypeDB.NVDNamespace, - } - } - return vulns -} diff --git a/pkg/process/v3/transformers/github/transform_test.go b/pkg/process/v3/transformers/github/transform_test.go deleted file mode 100644 index ff4c8af3..00000000 --- a/pkg/process/v3/transformers/github/transform_test.go +++ /dev/null @@ -1,198 +0,0 @@ -package github - -import ( - "os" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - testUtils "github.com/anchore/grype-db/pkg/process/internal/tests" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v3" -) - -func TestUnmarshalGitHubEntries(t *testing.T) { - f, err := os.Open("test-fixtures/github-github-python-0.json") - require.NoError(t, err) - defer testUtils.CloseFile(f) - - entries, err := unmarshal.GitHubAdvisoryEntries(f) - require.NoError(t, err) - - assert.Len(t, entries, 2) - -} - -func TestParseGitHubEntry(t *testing.T) { - expectedVulns := []grypeDB.Vulnerability{ - { - ID: "GHSA-p5wr-vp8g-q5p4", - VersionConstraint: ">=4.0,<4.3.12", - VersionFormat: "python", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2017-5524", - Namespace: grypeDB.NVDNamespace, - }, - }, - PackageName: "Plone", - Namespace: "github:python", - Fix: grypeDB.Fix{ - Versions: []string{"4.3.12"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "GHSA-p5wr-vp8g-q5p4", - VersionConstraint: ">=5.1a1,<5.1b1", - VersionFormat: "python", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2017-5524", - Namespace: grypeDB.NVDNamespace, - }, - }, - PackageName: "Plone", - Namespace: "github:python", - Fix: grypeDB.Fix{ - Versions: []string{"5.1b1"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "GHSA-p5wr-vp8g-q5p4", - VersionConstraint: ">=5.0rc1,<5.0.7", - VersionFormat: "python", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2017-5524", - Namespace: grypeDB.NVDNamespace, - }, - }, - PackageName: "Plone", - Namespace: "github:python", - Fix: grypeDB.Fix{ - Versions: []string{"5.0.7"}, - State: grypeDB.FixedState, - }, - }, - } - - expectedMetadata := grypeDB.VulnerabilityMetadata{ - ID: "GHSA-p5wr-vp8g-q5p4", - Namespace: "github:python", - RecordSource: "github:github:python", - DataSource: "https://github.com/advisories/GHSA-p5wr-vp8g-q5p4", - Severity: "Medium", - URLs: []string{"https://github.com/advisories/GHSA-p5wr-vp8g-q5p4"}, - Description: "Moderate severity vulnerability that affects Plone", - } - - f, err := os.Open("test-fixtures/github-github-python-1.json") - require.NoError(t, err) - defer testUtils.CloseFile(f) - - entries, err := unmarshal.GitHubAdvisoryEntries(f) - require.NoError(t, err) - - require.Len(t, entries, 1) - entry := entries[0] - - dataEntries, err := Transform(entry) - assert.NoError(t, err) - - var vulns []grypeDB.Vulnerability - for _, entry := range dataEntries { - switch vuln := entry.Data.(type) { - case grypeDB.Vulnerability: - vulns = append(vulns, vuln) - case grypeDB.VulnerabilityMetadata: - assert.Equal(t, expectedMetadata, vuln) - default: - t.Fatalf("unexpected condition: data entry does not have a vulnerability or a metadata") - } - } - - // check vulnerability - assert.Len(t, vulns, len(expectedVulns)) - - if diff := cmp.Diff(expectedVulns, vulns); diff != "" { - t.Errorf("vulnerabilities do not match (-want +got):\n%s", diff) - } -} - -func TestDefaultVersionFormatNpmGitHubEntry(t *testing.T) { - expectedVuln := grypeDB.Vulnerability{ - ID: "GHSA-vc9j-fhvv-8vrf", - VersionConstraint: "<=0.2.0-prerelease.20200709173451", - VersionFormat: "unknown", // TODO: this should reference a format, yes? (not a string) - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2020-14000", - Namespace: grypeDB.NVDNamespace, - }, - }, - PackageName: "scratch-vm", - Namespace: "github:npm", - Fix: grypeDB.Fix{ - Versions: []string{"0.2.0-prerelease.20200714185213"}, - State: grypeDB.FixedState, - }, - } - - expectedMetadata := grypeDB.VulnerabilityMetadata{ - ID: "GHSA-vc9j-fhvv-8vrf", - Namespace: "github:npm", - RecordSource: "github:github:npm", - DataSource: "https://github.com/advisories/GHSA-vc9j-fhvv-8vrf", - Severity: "High", - URLs: []string{"https://github.com/advisories/GHSA-vc9j-fhvv-8vrf"}, - Description: "Remote Code Execution in scratch-vm", - } - - f, err := os.Open("test-fixtures/github-github-npm-0.json") - require.NoError(t, err) - defer testUtils.CloseFile(f) - - entries, err := unmarshal.GitHubAdvisoryEntries(f) - require.NoError(t, err) - - require.Len(t, entries, 1) - - entry := entries[0] - - dataEntries, err := Transform(entry) - assert.NoError(t, err) - - for _, entry := range dataEntries { - switch vuln := entry.Data.(type) { - case grypeDB.Vulnerability: - assert.Equal(t, expectedVuln, vuln) - case grypeDB.VulnerabilityMetadata: - assert.Equal(t, expectedMetadata, vuln) - default: - t.Fatalf("unexpected condition: data entry does not have a vulnerability or a metadata") - } - } - - // check vulnerability - assert.Len(t, dataEntries, 2) -} - -func TestFilterWithdrawnEntries(t *testing.T) { - f, err := os.Open("test-fixtures/github-withdrawn.json") - require.NoError(t, err) - defer testUtils.CloseFile(f) - - entries, err := unmarshal.GitHubAdvisoryEntries(f) - require.NoError(t, err) - - require.Len(t, entries, 1) - entry := entries[0] - - dataEntries, err := Transform(entry) - assert.NoError(t, err) - assert.Nil(t, dataEntries) -} diff --git a/pkg/process/v3/transformers/msrc/test-fixtures/microsoft-msrc-0.json b/pkg/process/v3/transformers/msrc/test-fixtures/microsoft-msrc-0.json deleted file mode 100644 index 474b23b2..00000000 --- a/pkg/process/v3/transformers/msrc/test-fixtures/microsoft-msrc-0.json +++ /dev/null @@ -1,194 +0,0 @@ -[ - { - "cvss": { - "base_score": 7.8, - "temporal_score": 7, - "vector": "CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H/E:P/RL:O/RC:C" - }, - "fixed_in": [ - { - "id": "4493470", - "is_first": true, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4493470", - "https://support.microsoft.com/help/4493470" - ] - }, - { - "id": "4494440", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4494440", - "https://support.microsoft.com/help/4494440" - ] - }, - { - "id": "4503267", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4503267", - "https://support.microsoft.com/en-us/help/4503267" - ] - }, - { - "id": "4507460", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4507460", - "https://support.microsoft.com/help/4507460" - ] - }, - { - "id": "4512517", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4512517", - "https://support.microsoft.com/help/4512517" - ] - }, - { - "id": "4516044", - "is_first": false, - "is_latest": true, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4516044", - "https://support.microsoft.com/help/4516044" - ] - } - ], - "id": "CVE-2019-0671", - "link": "https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-0671", - "product": { - "family": "Windows", - "id": "10852", - "name": "Windows 10 Version 1607 for 32-bit Systems" - }, - "severity": "High", - "summary": "Microsoft Office Access Connectivity Engine Remote Code Execution Vulnerability", - "vulnerable": [ - "4480961", - "4483229", - "4487026", - "4489882" - ] - }, -{ - "cvss": { - "base_score": 4.4, - "temporal_score": 4, - "vector": "CVSS:3.0/AV:L/AC:H/PR:L/UI:R/S:U/C:N/I:N/A:H/E:P/RL:O/RC:C" - }, - "fixed_in": [ - { - "id": "4093119", - "is_first": true, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4093119" - ] - }, - { - "id": "4103723", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4103723" - ] - }, - { - "id": "4284880", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4284880" - ] - }, - { - "id": "4338814", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4338814" - ] - }, - { - "id": "4343887", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4343887" - ] - }, - { - "id": "4345418", - "is_first": false, - "is_latest": true, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4345418" - ] - }, - { - "id": "4457131", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4457131" - ] - }, - { - "id": "4462917", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4462917" - ] - }, - { - "id": "4467691", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4467691" - ] - }, - { - "id": "4471321", - "is_first": false, - "is_latest": true, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4471321" - ] - } - ], - "id": "CVE-2018-8116", - "link": "https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-8116", - "product": { - "family": "Windows", - "id": "10852", - "name": "Windows 10 Version 1607 for 32-bit Systems" - }, - "severity": "Medium", - "summary": "Microsoft Graphics Component Denial of Service Vulnerability", - "vulnerable": [ - "3213986", - "4013429", - "4015217", - "4019472", - "4022715", - "4025339", - "4034658", - "4038782", - "4041691", - "4048953", - "4053579", - "4056890", - "4074590", - "4088787" - ] - } -] diff --git a/pkg/process/v3/transformers/msrc/transform.go b/pkg/process/v3/transformers/msrc/transform.go deleted file mode 100644 index 14d84da9..00000000 --- a/pkg/process/v3/transformers/msrc/transform.go +++ /dev/null @@ -1,91 +0,0 @@ -package msrc - -import ( - "fmt" - - "github.com/anchore/grype-db/pkg/data" - "github.com/anchore/grype-db/pkg/process/internal/common" - "github.com/anchore/grype-db/pkg/process/v3/transformers" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v3" -) - -const ( - // TODO: tech debt from a previous design - feed = "microsoft" - groupPrefix = "msrc" -) - -// Transform gets called by the parser, which consumes entries from the JSON files previously pulled. Each VulnDBVulnerability represents -// a single unmarshalled entry from the feed service -func Transform(vulnerability unmarshal.MSRCVulnerability) ([]data.Entry, error) { - group := fmt.Sprintf("%s:%s", groupPrefix, vulnerability.Product.ID) - recordSource := grypeDB.RecordSource(feed, group) - entryNamespace, err := grypeDB.NamespaceForFeedGroup(feed, group) - if err != nil { - return nil, err - } - - // In anchore-enterprise windows analyzer, "base" represents unpatched windows images (images with no KBs). - // If a vulnerability exists for a Microsoft Product ID and the image has no KBs (which are patches), - // then the image must be vulnerable to the image. - //nolint:gocritic - versionConstraint := append(vulnerability.Vulnerable, "base") - - allVulns := []grypeDB.Vulnerability{ - { - ID: vulnerability.ID, - VersionConstraint: common.OrConstraints(versionConstraint...), - VersionFormat: "kb", - PackageName: vulnerability.Product.ID, - Namespace: entryNamespace, - Fix: getFix(vulnerability), - }, - } - - // create vulnerability metadata entry (a single entry keyed off of the vulnerability ID) - metadata := grypeDB.VulnerabilityMetadata{ - ID: vulnerability.ID, - DataSource: vulnerability.Link, - Namespace: entryNamespace, - RecordSource: recordSource, - Severity: vulnerability.Severity, - URLs: []string{vulnerability.Link}, - // There is no description for vulnerabilities from the feed service - // summary gives something like "windows information disclosure vulnerability" - //Description: vulnerability.Summary, - Cvss: []grypeDB.Cvss{ - { - Metrics: grypeDB.CvssMetrics{BaseScore: vulnerability.Cvss.BaseScore}, - Vector: vulnerability.Cvss.Vector, - }, - }, - } - - return transformers.NewEntries(allVulns, metadata), nil -} - -func getFix(entry unmarshal.MSRCVulnerability) grypeDB.Fix { - fixedInVersion := fixedInKB(entry) - fixState := grypeDB.FixedState - - if fixedInVersion == "" { - fixState = grypeDB.NotFixedState - } - - return grypeDB.Fix{ - Versions: []string{fixedInVersion}, - State: fixState, - } -} - -// fixedInKB finds the "latest" patch (KB id) amongst the available microsoft patches and returns it -// if the "latest" patch cannot be found, an error is returned -func fixedInKB(vulnerability unmarshal.MSRCVulnerability) string { - for _, fixedIn := range vulnerability.FixedIn { - if fixedIn.IsLatest { - return fixedIn.ID - } - } - return "" -} diff --git a/pkg/process/v3/transformers/msrc/transform_test.go b/pkg/process/v3/transformers/msrc/transform_test.go deleted file mode 100644 index c9e63760..00000000 --- a/pkg/process/v3/transformers/msrc/transform_test.go +++ /dev/null @@ -1,120 +0,0 @@ -package msrc - -import ( - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - testUtils "github.com/anchore/grype-db/pkg/process/internal/tests" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v3" -) - -func TestUnmarshalMsrcVulnerabilities(t *testing.T) { - f, err := os.Open("test-fixtures/microsoft-msrc-0.json") - require.NoError(t, err) - defer testUtils.CloseFile(f) - - entries, err := unmarshal.MSRCVulnerabilityEntries(f) - require.NoError(t, err) - - assert.Equal(t, len(entries), 2) -} - -func TestParseMSRCEntry(t *testing.T) { - expectedVulns := []struct { - vulnerability grypeDB.Vulnerability - metadata grypeDB.VulnerabilityMetadata - }{ - { - vulnerability: grypeDB.Vulnerability{ - ID: "CVE-2019-0671", - VersionConstraint: `4480961 || 4483229 || 4487026 || 4489882 || base`, - VersionFormat: "kb", - PackageName: "10852", - Namespace: "msrc:10852", - Fix: grypeDB.Fix{ - Versions: []string{"4516044"}, - State: grypeDB.FixedState, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2019-0671", - Severity: "High", - DataSource: "https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-0671", - URLs: []string{"https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-0671"}, - Description: "", - RecordSource: "microsoft:msrc:10852", - Namespace: "msrc:10852", - Cvss: []grypeDB.Cvss{ - { - Metrics: grypeDB.CvssMetrics{ - BaseScore: 7.8, - ImpactScore: nil, - }, - Vector: "CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H/E:P/RL:O/RC:C", - }, - }, - }, - }, - { - vulnerability: grypeDB.Vulnerability{ - ID: "CVE-2018-8116", - VersionConstraint: `3213986 || 4013429 || 4015217 || 4019472 || 4022715 || 4025339 || 4034658 || 4038782 || 4041691 || 4048953 || 4053579 || 4056890 || 4074590 || 4088787 || base`, - VersionFormat: "kb", - PackageName: "10852", - Namespace: "msrc:10852", - Fix: grypeDB.Fix{ - Versions: []string{"4345418"}, - State: grypeDB.FixedState, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2018-8116", - Namespace: "msrc:10852", - DataSource: "https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-8116", - RecordSource: "microsoft:msrc:10852", - Severity: "Medium", - URLs: []string{"https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-8116"}, - Description: "", - Cvss: []grypeDB.Cvss{ - { - Metrics: grypeDB.CvssMetrics{ - BaseScore: 4.4, - ImpactScore: nil, - }, - Vector: "CVSS:3.0/AV:L/AC:H/PR:L/UI:R/S:U/C:N/I:N/A:H/E:P/RL:O/RC:C", - }, - }, - }, - }, - } - - f, err := os.Open("test-fixtures/microsoft-msrc-0.json") - require.NoError(t, err) - defer testUtils.CloseFile(f) - - entries, err := unmarshal.MSRCVulnerabilityEntries(f) - require.NoError(t, err) - - require.Equal(t, len(entries), 2) - - for idx, entry := range entries { - dataEntries, err := Transform(entry) - require.NoError(t, err) - assert.Len(t, dataEntries, 2) - expected := expectedVulns[idx] - for _, entry := range dataEntries { - switch vuln := entry.Data.(type) { - case grypeDB.Vulnerability: - assert.Equal(t, expected.vulnerability, vuln) - case grypeDB.VulnerabilityMetadata: - assert.Equal(t, expected.metadata, vuln) - default: - t.Fatalf("unexpected condition: data entry does not have a vulnerability or a metadata") - } - } - } -} diff --git a/pkg/process/v3/transformers/nvd/test-fixtures/compound-pkg.json b/pkg/process/v3/transformers/nvd/test-fixtures/compound-pkg.json deleted file mode 100644 index 8e658dcd..00000000 --- a/pkg/process/v3/transformers/nvd/test-fixtures/compound-pkg.json +++ /dev/null @@ -1,115 +0,0 @@ -{ - "cve": { - "id": "CVE-2018-10189", - "sourceIdentifier": "cve@mitre.org", - "published": "2018-04-17T20:29:00.410", - "lastModified": "2018-05-23T14:41:49.073", - "vulnStatus": "Analyzed", - "descriptions": [ - { - "lang": "en", - "value": "An issue was discovered in Mautic 1.x and 2.x before 2.13.0. It is possible to systematically emulate tracking cookies per contact due to tracking the contact by their auto-incremented ID. Thus, a third party can manipulate the cookie value with +1 to systematically assume being tracked as each contact in Mautic. It is then possible to retrieve information about the contact through forms that have progressive profiling enabled." - }, - { - "lang": "es", - "value": "Se ha descubierto un problema en Mautic, en versiones 1.x y 2.x anteriores a la 2.13.0. Es posible emular de forma sistemática el rastreo de cookies por contacto debido al rastreo de contacto por su ID autoincrementada. Por lo tanto, un tercero puede manipular el valor de la cookie con un +1 para asumir sistemáticamente que se está rastreando como cada contacto en Mautic. Así, sería posible recuperar información sobre el contacto a través de formularios que tengan habilitada la generación de perfiles progresiva." - } - ], - "metrics": { - "cvssMetricV30": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "3.0", - "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", - "attackVector": "NETWORK", - "attackComplexity": "LOW", - "privilegesRequired": "NONE", - "userInteraction": "NONE", - "scope": "UNCHANGED", - "confidentialityImpact": "HIGH", - "integrityImpact": "NONE", - "availabilityImpact": "NONE", - "baseScore": 7.5, - "baseSeverity": "HIGH" - }, - "exploitabilityScore": 3.9, - "impactScore": 3.6 - } - ], - "cvssMetricV2": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "2.0", - "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", - "accessVector": "NETWORK", - "accessComplexity": "LOW", - "authentication": "NONE", - "confidentialityImpact": "PARTIAL", - "integrityImpact": "NONE", - "availabilityImpact": "NONE", - "baseScore": 5.0 - }, - "baseSeverity": "MEDIUM", - "exploitabilityScore": 10.0, - "impactScore": 2.9, - "acInsufInfo": false, - "obtainAllPrivilege": false, - "obtainUserPrivilege": false, - "obtainOtherPrivilege": false, - "userInteractionRequired": false - } - ] - }, - "weaknesses": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "description": [ - { - "lang": "en", - "value": "CWE-200" - } - ] - } - ], - "configurations": [ - { - "nodes": [ - { - "operator": "OR", - "negate": false, - "cpeMatch": [ - { - "vulnerable": true, - "criteria": "cpe:2.3:a:mautic:mautic:*:*:*:*:*:*:*:*", - "versionStartIncluding": "1.0.0", - "versionEndIncluding": "1.4.1", - "matchCriteriaId": "5779710D-099E-40EE-8DF3-55BD3179A50C" - }, - { - "vulnerable": true, - "criteria": "cpe:2.3:a:mautic:mautic:*:*:*:*:*:*:*:*", - "versionStartIncluding": "2.0.0", - "versionEndExcluding": "2.13.0", - "matchCriteriaId": "4EFAEE48-4AEF-4F8C-95E0-6E8D848D900F" - } - ] - } - ] - } - ], - "references": [ - { - "url": "https://github.com/mautic/mautic/releases/tag/2.13.0", - "source": "cve@mitre.org", - "tags": [ - "Third Party Advisory" - ] - } - ] - } -} diff --git a/pkg/process/v3/transformers/nvd/test-fixtures/invalid_cpe.json b/pkg/process/v3/transformers/nvd/test-fixtures/invalid_cpe.json deleted file mode 100644 index eac2ebd4..00000000 --- a/pkg/process/v3/transformers/nvd/test-fixtures/invalid_cpe.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "cve": { - "id": "CVE-2015-8978", - "sourceIdentifier": "cve@mitre.org", - "published": "2016-11-22T17:59:00.180", - "lastModified": "2016-11-28T19:50:59.600", - "vulnStatus": "Modified", - "descriptions": [ - { - "lang": "en", - "value": "In Soap Lite (aka the SOAP::Lite extension for Perl) 1.14 and earlier, an example attack consists of defining 10 or more XML entities, each defined as consisting of 10 of the previous entity, with the document consisting of a single instance of the largest entity, which expands to one billion copies of the first entity. The amount of computer memory used for handling an external SOAP call would likely exceed that available to the process parsing the XML." - }, - { - "lang": "es", - "value": "En Soap Lite (también conocido como la extensión SOAP::Lite para Perl) 1.14 y versiones anteriores, un ejemplo de ataque consiste en definir 10 o más entidades XML, cada una definida como consistente de 10 de la entidad anterior, con el documento consistente de una única instancia de la entidad más grande, que se expande a mil millones de copias de la primera entidad. La suma de la memoria del ordenador utilizada para manejar una llamada SOAP externa probablemente superaría el disponible para el proceso de análisis del XML." - } - ], - "metrics": { - "cvssMetricV30": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "3.0", - "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - "attackVector": "NETWORK", - "attackComplexity": "LOW", - "privilegesRequired": "NONE", - "userInteraction": "NONE", - "scope": "UNCHANGED", - "confidentialityImpact": "NONE", - "integrityImpact": "NONE", - "availabilityImpact": "HIGH", - "baseScore": 7.5, - "baseSeverity": "HIGH" - }, - "exploitabilityScore": 3.9, - "impactScore": 3.6 - } - ], - "cvssMetricV2": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "2.0", - "vectorString": "AV:N/AC:L/Au:N/C:N/I:N/A:P", - "accessVector": "NETWORK", - "accessComplexity": "LOW", - "authentication": "NONE", - "confidentialityImpact": "NONE", - "integrityImpact": "NONE", - "availabilityImpact": "PARTIAL", - "baseScore": 5.0 - }, - "baseSeverity": "MEDIUM", - "exploitabilityScore": 10.0, - "impactScore": 2.9, - "acInsufInfo": false, - "obtainAllPrivilege": false, - "obtainUserPrivilege": false, - "obtainOtherPrivilege": false, - "userInteractionRequired": false - } - ] - }, - "weaknesses": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "description": [ - { - "lang": "en", - "value": "CWE-399" - } - ] - } - ], - "configurations": [ - { - "nodes": [ - { - "operator": "OR", - "negate": false, - "cpeMatch": [ - { - "vulnerable": true, - "criteria": "cpe:2.3:a:soap::lite_project:soap::lite:*:*:*:*:*:perl:*:*", - "versionEndIncluding": "1.14", - "matchCriteriaId": "FB4DACB9-2E9E-4CBE-825F-FC0303D8CC86" - } - ] - } - ] - } - ], - "references": [ - { - "url": "http://cpansearch.perl.org/src/PHRED/SOAP-Lite-1.20/Changes", - "source": "cve@mitre.org", - "tags": [ - "Vendor Advisory" - ] - }, - { - "url": "http://www.securityfocus.com/bid/94487", - "source": "cve@mitre.org" - } - ] - } -} diff --git a/pkg/process/v3/transformers/nvd/test-fixtures/single-package-multi-distro.json b/pkg/process/v3/transformers/nvd/test-fixtures/single-package-multi-distro.json deleted file mode 100644 index ed108475..00000000 --- a/pkg/process/v3/transformers/nvd/test-fixtures/single-package-multi-distro.json +++ /dev/null @@ -1,174 +0,0 @@ -{ - "cve": { - "id": "CVE-2018-1000222", - "sourceIdentifier": "cve@mitre.org", - "published": "2018-08-20T20:29:01.347", - "lastModified": "2020-03-31T02:15:12.667", - "vulnStatus": "Modified", - "descriptions": [ - { - "lang": "en", - "value": "Libgd version 2.2.5 contains a Double Free Vulnerability vulnerability in gdImageBmpPtr Function that can result in Remote Code Execution . This attack appear to be exploitable via Specially Crafted Jpeg Image can trigger double free. This vulnerability appears to have been fixed in after commit ac16bdf2d41724b5a65255d4c28fb0ec46bc42f5." - }, - { - "lang": "es", - "value": "Libgd 2.2.5 contiene una vulnerabilidad de doble liberación (double free) en la función gdImageBmpPtr que puede resultar en la ejecución remota de código. Este ataque parece ser explotable mediante una imagen JPEG especialmente manipulada que desencadene una doble liberación (double free). La vulnerabilidad parece haber sido solucionada tras el commit con ID ac16bdf2d41724b5a65255d4c28fb0ec46bc42f5." - } - ], - "metrics": { - "cvssMetricV30": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "3.0", - "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - "attackVector": "NETWORK", - "attackComplexity": "LOW", - "privilegesRequired": "NONE", - "userInteraction": "REQUIRED", - "scope": "UNCHANGED", - "confidentialityImpact": "HIGH", - "integrityImpact": "HIGH", - "availabilityImpact": "HIGH", - "baseScore": 8.8, - "baseSeverity": "HIGH" - }, - "exploitabilityScore": 2.8, - "impactScore": 5.9 - } - ], - "cvssMetricV2": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "2.0", - "vectorString": "AV:N/AC:M/Au:N/C:P/I:P/A:P", - "accessVector": "NETWORK", - "accessComplexity": "MEDIUM", - "authentication": "NONE", - "confidentialityImpact": "PARTIAL", - "integrityImpact": "PARTIAL", - "availabilityImpact": "PARTIAL", - "baseScore": 6.8 - }, - "baseSeverity": "MEDIUM", - "exploitabilityScore": 8.6, - "impactScore": 6.4, - "acInsufInfo": false, - "obtainAllPrivilege": false, - "obtainUserPrivilege": false, - "obtainOtherPrivilege": false, - "userInteractionRequired": true - } - ] - }, - "weaknesses": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "description": [ - { - "lang": "en", - "value": "CWE-415" - } - ] - } - ], - "configurations": [ - { - "nodes": [ - { - "operator": "OR", - "negate": false, - "cpeMatch": [ - { - "vulnerable": true, - "criteria": "cpe:2.3:a:libgd:libgd:2.2.5:*:*:*:*:*:*:*", - "matchCriteriaId": "C257CC1C-BF6A-4125-AA61-9C2D09096084" - } - ] - } - ] - }, - { - "nodes": [ - { - "operator": "OR", - "negate": false, - "cpeMatch": [ - { - "vulnerable": true, - "criteria": "cpe:2.3:o:canonical:ubuntu_linux:14.04:*:*:*:lts:*:*:*", - "matchCriteriaId": "B5A6F2F3-4894-4392-8296-3B8DD2679084" - }, - { - "vulnerable": true, - "criteria": "cpe:2.3:o:canonical:ubuntu_linux:16.04:*:*:*:lts:*:*:*", - "matchCriteriaId": "F7016A2A-8365-4F1A-89A2-7A19F2BCAE5B" - }, - { - "vulnerable": true, - "criteria": "cpe:2.3:o:canonical:ubuntu_linux:18.04:*:*:*:lts:*:*:*", - "matchCriteriaId": "23A7C53F-B80F-4E6A-AFA9-58EEA84BE11D" - } - ] - } - ] - }, - { - "nodes": [ - { - "operator": "OR", - "negate": false, - "cpeMatch": [ - { - "vulnerable": true, - "criteria": "cpe:2.3:o:debian:debian_linux:8.0:*:*:*:*:*:*:*", - "matchCriteriaId": "C11E6FB0-C8C0-4527-9AA0-CB9B316F8F43" - } - ] - } - ] - } - ], - "references": [ - { - "url": "https://github.com/libgd/libgd/issues/447", - "source": "cve@mitre.org", - "tags": [ - "Issue Tracking", - "Third Party Advisory" - ] - }, - { - "url": "https://lists.debian.org/debian-lts-announce/2019/01/msg00028.html", - "source": "cve@mitre.org", - "tags": [ - "Mailing List", - "Third Party Advisory" - ] - }, - { - "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/3CZ2QADQTKRHTGB2AHD7J4QQNDLBEMM6/", - "source": "cve@mitre.org" - }, - { - "url": "https://security.gentoo.org/glsa/201903-18", - "source": "cve@mitre.org", - "tags": [ - "Third Party Advisory" - ] - }, - { - "url": "https://usn.ubuntu.com/3755-1/", - "source": "cve@mitre.org", - "tags": [ - "Mitigation", - "Third Party Advisory" - ] - } - ] - } -} diff --git a/pkg/process/v3/transformers/nvd/test-fixtures/unmarshal-test.json b/pkg/process/v3/transformers/nvd/test-fixtures/unmarshal-test.json deleted file mode 100644 index 2dc698fa..00000000 --- a/pkg/process/v3/transformers/nvd/test-fixtures/unmarshal-test.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "cve": { - "id": "CVE-2003-0349", - "sourceIdentifier": "cve@mitre.org", - "published": "2003-07-24T04:00:00.000", - "lastModified": "2018-10-12T21:32:41.083", - "vulnStatus": "Modified", - "descriptions": [ - { - "lang": "en", - "value": "Buffer overflow in the streaming media component for logging multicast requests in the ISAPI for the logging capability of Microsoft Windows Media Services (nsiislog.dll), as installed in IIS 5.0, allows remote attackers to execute arbitrary code via a large POST request to nsiislog.dll." - }, - { - "lang": "es", - "value": "Desbordamiento de búfer en el componente de secuenciamiento (streaming) de medios para registrar peticiones de multidifusión en la librería ISAPI de la capacidad de registro (logging) de Microsoft Windows Media Services (nsiislog.dll), como el instalado en IIS 5.9, permite a atacantes remotos ejecutar código arbitrario mediante una petición POST larga a nsiislog.dll." - } - ], - "metrics": { - "cvssMetricV2": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "2.0", - "vectorString": "AV:N/AC:L/Au:N/C:P/I:P/A:P", - "accessVector": "NETWORK", - "accessComplexity": "LOW", - "authentication": "NONE", - "confidentialityImpact": "PARTIAL", - "integrityImpact": "PARTIAL", - "availabilityImpact": "PARTIAL", - "baseScore": 7.5 - }, - "baseSeverity": "HIGH", - "exploitabilityScore": 10.0, - "impactScore": 6.4, - "acInsufInfo": false, - "obtainAllPrivilege": false, - "obtainUserPrivilege": true, - "obtainOtherPrivilege": false, - "userInteractionRequired": false - } - ] - }, - "weaknesses": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "description": [ - { - "lang": "en", - "value": "NVD-CWE-Other" - } - ] - } - ], - "configurations": [ - { - "nodes": [ - { - "operator": "OR", - "negate": false, - "cpeMatch": [ - { - "vulnerable": true, - "criteria": "cpe:2.3:o:microsoft:windows_2000:*:*:*:*:*:*:*:*", - "matchCriteriaId": "4E545C63-FE9C-4CA1-AF0F-D999D84D2AFD" - } - ] - } - ] - } - ], - "references": [ - { - "url": "http://marc.info/?l=bugtraq&m=105665030925504&w=2", - "source": "cve@mitre.org" - }, - { - "url": "http://securitytracker.com/id?1007059", - "source": "cve@mitre.org" - }, - { - "url": "http://www.kb.cert.org/vuls/id/113716", - "source": "cve@mitre.org", - "tags": [ - "US Government Resource" - ] - }, - { - "url": "http://www.ntbugtraq.com/default.asp?pid=36&sid=1&A2=ind0306&L=NTBUGTRAQ&P=R4563", - "source": "cve@mitre.org", - "tags": [ - "Exploit", - "Patch", - "Vendor Advisory" - ] - }, - { - "url": "https://docs.microsoft.com/en-us/security-updates/securitybulletins/2003/ms03-022", - "source": "cve@mitre.org" - }, - { - "url": "https://oval.cisecurity.org/repository/search/definition/oval%3Aorg.mitre.oval%3Adef%3A938", - "source": "cve@mitre.org" - } - ] - } -} diff --git a/pkg/process/v3/transformers/nvd/test-fixtures/version-range.json b/pkg/process/v3/transformers/nvd/test-fixtures/version-range.json deleted file mode 100644 index 3df5b86d..00000000 --- a/pkg/process/v3/transformers/nvd/test-fixtures/version-range.json +++ /dev/null @@ -1,121 +0,0 @@ -{ - "cve": { - "id": "CVE-2018-5487", - "sourceIdentifier": "security-alert@netapp.com", - "published": "2018-05-24T14:29:00.390", - "lastModified": "2018-07-05T13:52:30.627", - "vulnStatus": "Analyzed", - "descriptions": [ - { - "lang": "en", - "value": "NetApp OnCommand Unified Manager for Linux versions 7.2 through 7.3 ship with the Java Management Extension Remote Method Invocation (JMX RMI) service bound to the network, and are susceptible to unauthenticated remote code execution." - }, - { - "lang": "es", - "value": "NetApp OnCommand Unified Manager for Linux, de la versión 7.2 hasta la 7.3, se distribuye con el servicio Java Management Extension Remote Method Invocation (JMX RMI) enlazado a la red y es susceptible a la ejecución remota de código sin autenticación." - } - ], - "metrics": { - "cvssMetricV30": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "3.0", - "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", - "attackVector": "NETWORK", - "attackComplexity": "LOW", - "privilegesRequired": "NONE", - "userInteraction": "NONE", - "scope": "UNCHANGED", - "confidentialityImpact": "HIGH", - "integrityImpact": "HIGH", - "availabilityImpact": "HIGH", - "baseScore": 9.8, - "baseSeverity": "CRITICAL" - }, - "exploitabilityScore": 3.9, - "impactScore": 5.9 - } - ], - "cvssMetricV2": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "2.0", - "vectorString": "AV:N/AC:L/Au:N/C:P/I:P/A:P", - "accessVector": "NETWORK", - "accessComplexity": "LOW", - "authentication": "NONE", - "confidentialityImpact": "PARTIAL", - "integrityImpact": "PARTIAL", - "availabilityImpact": "PARTIAL", - "baseScore": 7.5 - }, - "baseSeverity": "HIGH", - "exploitabilityScore": 10.0, - "impactScore": 6.4, - "acInsufInfo": true, - "obtainAllPrivilege": false, - "obtainUserPrivilege": false, - "obtainOtherPrivilege": false, - "userInteractionRequired": false - } - ] - }, - "weaknesses": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "description": [ - { - "lang": "en", - "value": "CWE-20" - } - ] - } - ], - "configurations": [ - { - "operator": "AND", - "nodes": [ - { - "operator": "OR", - "negate": false, - "cpeMatch": [ - { - "vulnerable": true, - "criteria": "cpe:2.3:a:netapp:oncommand_unified_manager:*:*:*:*:*:*:*:*", - "versionStartIncluding": "7.2", - "versionEndIncluding": "7.3", - "matchCriteriaId": "A5949307-3E9B-441F-B008-81A0E0228DC0" - } - ] - }, - { - "operator": "OR", - "negate": false, - "cpeMatch": [ - { - "vulnerable": false, - "criteria": "cpe:2.3:o:linux:linux_kernel:-:*:*:*:*:*:*:*", - "matchCriteriaId": "703AF700-7A70-47E2-BC3A-7FD03B3CA9C1" - } - ] - } - ] - } - ], - "references": [ - { - "url": "https://security.netapp.com/advisory/ntap-20180523-0001/", - "source": "security-alert@netapp.com", - "tags": [ - "Patch", - "Vendor Advisory" - ] - } - ] - } -} diff --git a/pkg/process/v3/transformers/nvd/transform.go b/pkg/process/v3/transformers/nvd/transform.go deleted file mode 100644 index 48cfc5eb..00000000 --- a/pkg/process/v3/transformers/nvd/transform.go +++ /dev/null @@ -1,95 +0,0 @@ -package nvd - -import ( - "fmt" - - "github.com/anchore/grype-db/internal" - "github.com/anchore/grype-db/pkg/data" - "github.com/anchore/grype-db/pkg/process/v3/transformers" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - "github.com/anchore/grype-db/pkg/provider/unmarshal/nvd" - grypeDB "github.com/anchore/grype/grype/db/v3" -) - -const ( - // TODO: tech debt from a previous design - feed = "nvdv2" - group = "nvdv2:cves" -) - -func Transform(vulnerability unmarshal.NVDVulnerability) ([]data.Entry, error) { - recordSource := grypeDB.RecordSource(feed, group) - entryNamespace, err := grypeDB.NamespaceForFeedGroup(feed, group) - if err != nil { - return nil, err - } - - uniquePkgs := findUniquePkgs(vulnerability.Configurations...) - - if err != nil { - return nil, fmt.Errorf("unable to parse NVD entry: %w", err) - } - - // extract all links - var links []string - for _, externalRefs := range vulnerability.References { - // TODO: should we capture other information here? - if externalRefs.URL != "" { - links = append(links, externalRefs.URL) - } - } - - // duplicate the vulnerabilities based on the set of unique packages the vulnerability is for - var allVulns []grypeDB.Vulnerability - for _, p := range uniquePkgs.All() { - matches := uniquePkgs.Matches(p) - cpes := internal.NewStringSet() - for _, m := range matches { - cpes.Add(m.Criteria) - } - - // create vulnerability entry - allVulns = append(allVulns, grypeDB.Vulnerability{ - ID: vulnerability.ID, - VersionConstraint: buildConstraints(matches), - VersionFormat: "unknown", - PackageName: p.Product, - Namespace: entryNamespace, - CPEs: cpes.ToSlice(), - Fix: grypeDB.Fix{ - State: grypeDB.UnknownFixState, - }, - }) - } - - // create vulnerability metadata entry (a single entry keyed off of the vulnerability ID) - allCVSS := vulnerability.CVSS() - metadata := grypeDB.VulnerabilityMetadata{ - ID: vulnerability.ID, - DataSource: "https://nvd.nist.gov/vuln/detail/" + vulnerability.ID, - Namespace: entryNamespace, - RecordSource: recordSource, - Severity: nvd.CvssSummaries(allCVSS).Sorted().Severity(), - URLs: links, - Description: vulnerability.Description(), - Cvss: getCvss(allCVSS...), - } - - return transformers.NewEntries(allVulns, metadata), nil -} - -func getCvss(cvss ...nvd.CvssSummary) []grypeDB.Cvss { - var results []grypeDB.Cvss - for _, c := range cvss { - results = append(results, grypeDB.Cvss{ - Version: c.Version, - Vector: c.Vector, - Metrics: grypeDB.CvssMetrics{ - BaseScore: c.BaseScore, - ExploitabilityScore: c.ExploitabilityScore, - ImpactScore: c.ImpactScore, - }, - }) - } - return results -} diff --git a/pkg/process/v3/transformers/nvd/transform_test.go b/pkg/process/v3/transformers/nvd/transform_test.go deleted file mode 100644 index 47232461..00000000 --- a/pkg/process/v3/transformers/nvd/transform_test.go +++ /dev/null @@ -1,257 +0,0 @@ -package nvd - -import ( - "os" - "testing" - - "github.com/go-test/deep" - "github.com/google/go-cmp/cmp" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - testUtils "github.com/anchore/grype-db/pkg/process/internal/tests" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v3" -) - -func TestUnmarshalNVDVulnerabilitiesEntries(t *testing.T) { - f, err := os.Open("test-fixtures/unmarshal-test.json") - require.NoError(t, err) - defer testUtils.CloseFile(f) - - entries, err := unmarshal.NvdVulnerabilityEntries(f) - require.NoError(t, err) - - assert.Len(t, entries, 1) -} - -func TestParseAllNVDVulnerabilityEntries(t *testing.T) { - - tests := []struct { - name string - numEntries int - fixture string - vulns []grypeDB.Vulnerability - metadata grypeDB.VulnerabilityMetadata - }{ - { - name: "AppVersionRange", - numEntries: 1, - fixture: "test-fixtures/version-range.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2018-5487", - PackageName: "oncommand_unified_manager", - VersionConstraint: ">= 7.2, <= 7.3", - VersionFormat: "unknown", // TODO: this should reference a format, yes? (not a string) - Namespace: "nvd", - CPEs: []string{"cpe:2.3:a:netapp:oncommand_unified_manager:*:*:*:*:*:*:*:*"}, - Fix: grypeDB.Fix{ - State: "unknown", - }, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2018-5487", - DataSource: "https://nvd.nist.gov/vuln/detail/CVE-2018-5487", - Namespace: "nvd", - RecordSource: "nvdv2:nvdv2:cves", - Severity: "Critical", - URLs: []string{"https://security.netapp.com/advisory/ntap-20180523-0001/"}, - Description: "NetApp OnCommand Unified Manager for Linux versions 7.2 through 7.3 ship with the Java Management Extension Remote Method Invocation (JMX RMI) service bound to the network, and are susceptible to unauthenticated remote code execution.", - Cvss: []grypeDB.Cvss{ - { - Metrics: grypeDB.NewCvssMetrics( - 7.5, - 10, - 6.4, - ), - Vector: "AV:N/AC:L/Au:N/C:P/I:P/A:P", - Version: "2.0", - }, - { - Metrics: grypeDB.NewCvssMetrics( - 9.8, - 3.9, - 5.9, - ), - Vector: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", - Version: "3.0", - }, - }, - }, - }, - { - name: "App+OS", - numEntries: 1, - fixture: "test-fixtures/single-package-multi-distro.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2018-1000222", - PackageName: "libgd", - VersionConstraint: "= 2.2.5", - VersionFormat: "unknown", // TODO: this should reference a format, yes? (not a string) - Namespace: "nvd", - CPEs: []string{"cpe:2.3:a:libgd:libgd:2.2.5:*:*:*:*:*:*:*"}, - Fix: grypeDB.Fix{ - State: "unknown", - }, - }, - // TODO: Question: should this match also the OS's? (as in the vulnerable_cpes list)... this seems wrong! - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2018-1000222", - DataSource: "https://nvd.nist.gov/vuln/detail/CVE-2018-1000222", - Namespace: "nvd", - RecordSource: "nvdv2:nvdv2:cves", - Severity: "High", - URLs: []string{"https://github.com/libgd/libgd/issues/447", "https://lists.debian.org/debian-lts-announce/2019/01/msg00028.html", "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/3CZ2QADQTKRHTGB2AHD7J4QQNDLBEMM6/", "https://security.gentoo.org/glsa/201903-18", "https://usn.ubuntu.com/3755-1/"}, - Description: "Libgd version 2.2.5 contains a Double Free Vulnerability vulnerability in gdImageBmpPtr Function that can result in Remote Code Execution . This attack appear to be exploitable via Specially Crafted Jpeg Image can trigger double free. This vulnerability appears to have been fixed in after commit ac16bdf2d41724b5a65255d4c28fb0ec46bc42f5.", - Cvss: []grypeDB.Cvss{ - { - Metrics: grypeDB.NewCvssMetrics( - 6.8, - 8.6, - 6.4, - ), - Vector: "AV:N/AC:M/Au:N/C:P/I:P/A:P", - Version: "2.0", - }, - { - Metrics: grypeDB.NewCvssMetrics( - 8.8, - 2.8, - 5.9, - ), - Vector: "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - Version: "3.0", - }, - }, - }, - }, - { - name: "AppCompoundVersionRange", - numEntries: 1, - fixture: "test-fixtures/compound-pkg.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2018-10189", - PackageName: "mautic", - VersionConstraint: ">= 1.0.0, <= 1.4.1 || >= 2.0.0, < 2.13.0", - VersionFormat: "unknown", - Namespace: "nvd", - CPEs: []string{"cpe:2.3:a:mautic:mautic:*:*:*:*:*:*:*:*"}, // note: entry was dedupicated - Fix: grypeDB.Fix{ - State: "unknown", - }, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2018-10189", - DataSource: "https://nvd.nist.gov/vuln/detail/CVE-2018-10189", - Namespace: "nvd", - RecordSource: "nvdv2:nvdv2:cves", - Severity: "High", - URLs: []string{"https://github.com/mautic/mautic/releases/tag/2.13.0"}, - Description: "An issue was discovered in Mautic 1.x and 2.x before 2.13.0. It is possible to systematically emulate tracking cookies per contact due to tracking the contact by their auto-incremented ID. Thus, a third party can manipulate the cookie value with +1 to systematically assume being tracked as each contact in Mautic. It is then possible to retrieve information about the contact through forms that have progressive profiling enabled.", - Cvss: []grypeDB.Cvss{ - { - Metrics: grypeDB.NewCvssMetrics( - 5, - 10, - 2.9, - ), - Vector: "AV:N/AC:L/Au:N/C:P/I:N/A:N", - Version: "2.0", - }, - { - Metrics: grypeDB.NewCvssMetrics( - 7.5, - 3.9, - 3.6, - ), - Vector: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", - Version: "3.0", - }, - }, - }, - }, - { - // we always keep the metadata even though there are no vulnerability entries for it - name: "InvalidCPE", - numEntries: 1, - fixture: "test-fixtures/invalid_cpe.json", - vulns: nil, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2015-8978", - Namespace: "nvd", - DataSource: "https://nvd.nist.gov/vuln/detail/CVE-2015-8978", - RecordSource: "nvdv2:nvdv2:cves", - Severity: "High", - URLs: []string{ - "http://cpansearch.perl.org/src/PHRED/SOAP-Lite-1.20/Changes", - "http://www.securityfocus.com/bid/94487", - }, - Description: "In Soap Lite (aka the SOAP::Lite extension for Perl) 1.14 and earlier, an example attack consists of defining 10 or more XML entities, each defined as consisting of 10 of the previous entity, with the document consisting of a single instance of the largest entity, which expands to one billion copies of the first entity. The amount of computer memory used for handling an external SOAP call would likely exceed that available to the process parsing the XML.", - Cvss: []grypeDB.Cvss{ - { - Metrics: grypeDB.NewCvssMetrics( - 5, - 10, - 2.9, - ), - Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P", - Version: "2.0", - }, - { - Metrics: grypeDB.NewCvssMetrics( - 7.5, - 3.9, - 3.6, - ), - Vector: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - Version: "3.0", - }, - }, - }, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - f, err := os.Open(test.fixture) - require.NoError(t, err) - t.Cleanup(func() { - assert.NoError(t, f.Close()) - }) - - entries, err := unmarshal.NvdVulnerabilityEntries(f) - require.NoError(t, err) - - var vulns []grypeDB.Vulnerability - for _, entry := range entries { - dataEntries, err := Transform(entry.Cve) - require.NoError(t, err) - - for _, entry := range dataEntries { - switch vuln := entry.Data.(type) { - case grypeDB.Vulnerability: - vulns = append(vulns, vuln) - case grypeDB.VulnerabilityMetadata: - // check metadata - if diff := deep.Equal(test.metadata, vuln); diff != nil { - for _, d := range diff { - t.Errorf("metadata diff: %+v", d) - } - } - default: - t.Fatalf("unexpected condition: data entry does not have a vulnerability or a metadata") - } - } - } - - if diff := cmp.Diff(test.vulns, vulns); diff != "" { - t.Errorf("vulnerabilities do not match (-want +got):\n%s", diff) - } - }) - } -} diff --git a/pkg/process/v3/transformers/nvd/unique_pkg.go b/pkg/process/v3/transformers/nvd/unique_pkg.go deleted file mode 100644 index 081e972b..00000000 --- a/pkg/process/v3/transformers/nvd/unique_pkg.go +++ /dev/null @@ -1,115 +0,0 @@ -package nvd - -import ( - "fmt" - "strings" - - "github.com/umisama/go-cpe" - - "github.com/anchore/grype-db/internal/log" - "github.com/anchore/grype-db/pkg/process/internal/common" - "github.com/anchore/grype-db/pkg/provider/unmarshal/nvd" -) - -const ( - ANY = "*" - NA = "-" -) - -type pkgCandidate struct { - Product string - Vendor string - TargetSoftware string -} - -func (p pkgCandidate) String() string { - return fmt.Sprintf("%s|%s|%s", p.Vendor, p.Product, p.TargetSoftware) -} - -func newPkgCandidate(match nvd.CpeMatch) (*pkgCandidate, error) { - // we are only interested in packages that are vulnerable (not related to secondary match conditioning) - if !match.Vulnerable { - return nil, nil - } - - c, err := cpe.NewItemFromFormattedString(match.Criteria) - if err != nil { - return nil, fmt.Errorf("unable to create uniquePkgEntry from '%s': %w", match.Criteria, err) - } - - // we are only interested in applications, not hardware or operating systems - if c.Part() != cpe.Application { - return nil, nil - } - - return &pkgCandidate{ - Product: c.Product().String(), - Vendor: c.Vendor().String(), - TargetSoftware: c.TargetSw().String(), - }, nil -} - -func findUniquePkgs(cfgs ...nvd.Configuration) uniquePkgTracker { - set := newUniquePkgTracker() - for _, c := range cfgs { - _findUniquePkgs(set, c.Nodes...) - } - return set -} - -func _findUniquePkgs(set uniquePkgTracker, ns ...nvd.Node) { - if len(ns) == 0 { - return - } - for _, node := range ns { - for _, match := range node.CpeMatch { - candidate, err := newPkgCandidate(match) - if err != nil { - // Do not halt all execution because of being unable to create - // a PkgCandidate. This can happen when a CPE is invalid which - // could avoid creating a database - log.Debugf("unable processing pkg: %v", err) - continue - } - if candidate != nil { - set.Add(*candidate, match) - } - } - } -} - -func buildConstraints(matches []nvd.CpeMatch) string { - constraints := make([]string, 0) - for _, match := range matches { - constraints = append(constraints, buildConstraint(match)) - } - return common.OrConstraints(constraints...) -} - -func buildConstraint(match nvd.CpeMatch) string { - constraints := make([]string, 0) - if match.VersionStartIncluding != nil && *match.VersionStartIncluding != "" { - constraints = append(constraints, fmt.Sprintf(">= %s", *match.VersionStartIncluding)) - } else if match.VersionStartExcluding != nil && *match.VersionStartExcluding != "" { - constraints = append(constraints, fmt.Sprintf("> %s", *match.VersionStartExcluding)) - } - - if match.VersionEndIncluding != nil && *match.VersionEndIncluding != "" { - constraints = append(constraints, fmt.Sprintf("<= %s", *match.VersionEndIncluding)) - } else if match.VersionEndExcluding != nil && *match.VersionEndExcluding != "" { - constraints = append(constraints, fmt.Sprintf("< %s", *match.VersionEndExcluding)) - } - - if len(constraints) == 0 { - c, err := cpe.NewItemFromFormattedString(match.Criteria) - if err != nil { - return "" - } - version := c.Version().String() - if version != ANY && version != NA { - constraints = append(constraints, fmt.Sprintf("= %s", version)) - } - } - - return strings.Join(constraints, ", ") -} diff --git a/pkg/process/v3/transformers/nvd/unique_pkg_test.go b/pkg/process/v3/transformers/nvd/unique_pkg_test.go deleted file mode 100644 index dc662c36..00000000 --- a/pkg/process/v3/transformers/nvd/unique_pkg_test.go +++ /dev/null @@ -1,353 +0,0 @@ -package nvd - -import ( - "testing" - - "github.com/sergi/go-diff/diffmatchpatch" - - "github.com/anchore/grype-db/pkg/provider/unmarshal/nvd" -) - -func newUniquePkgTrackerFromSlice(candidates []pkgCandidate) uniquePkgTracker { - set := newUniquePkgTracker() - for _, c := range candidates { - set[c] = nil - } - return set -} - -func TestFindUniquePkgs(t *testing.T) { - tests := []struct { - name string - nodes []nvd.Node - expected uniquePkgTracker - }{ - { - name: "simple-match", - nodes: []nvd.Node{ - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:2.2.0:*:*:*:*:target:*:*", - Vulnerable: true, - }, - }, - }, - }, - expected: newUniquePkgTrackerFromSlice( - []pkgCandidate{ - { - Product: "product", - Vendor: "vendor", - TargetSoftware: "target", - }, - }), - }, - { - name: "skip-hw", - nodes: []nvd.Node{ - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:h:vendor:product:2.2.0:*:*:*:*:target:*:*", - Vulnerable: true, - }, - }, - }, - }, - expected: newUniquePkgTrackerFromSlice([]pkgCandidate{}), - }, - { - name: "skip-os", - nodes: []nvd.Node{ - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:o:vendor:product:2.2.0:*:*:*:*:target:*:*", - Vulnerable: true, - }, - }, - }, - }, - expected: newUniquePkgTrackerFromSlice([]pkgCandidate{}), - }, - { - name: "duplicate-by-product", - nodes: []nvd.Node{ - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:productA:3.3.3:*:*:*:*:target:*:*", - Vulnerable: true, - }, - { - Criteria: "cpe:2.3:a:vendor:productB:2.2.0:*:*:*:*:target:*:*", - Vulnerable: true, - }, - }, - Operator: "OR", - }, - }, - expected: newUniquePkgTrackerFromSlice( - []pkgCandidate{ - { - Product: "productA", - Vendor: "vendor", - TargetSoftware: "target", - }, - { - Product: "productB", - Vendor: "vendor", - TargetSoftware: "target", - }, - }), - }, - { - name: "duplicate-by-target", - nodes: []nvd.Node{ - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:3.3.3:*:*:*:*:targetA:*:*", - Vulnerable: true, - }, - { - Criteria: "cpe:2.3:a:vendor:product:2.2.0:*:*:*:*:targetB:*:*", - Vulnerable: true, - }, - }, - Operator: "OR", - }, - }, - expected: newUniquePkgTrackerFromSlice( - []pkgCandidate{ - { - Product: "product", - Vendor: "vendor", - TargetSoftware: "targetA", - }, - { - Product: "product", - Vendor: "vendor", - TargetSoftware: "targetB", - }, - }), - }, - { - name: "duplicate-by-vendor", - nodes: []nvd.Node{ - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendorA:product:3.3.3:*:*:*:*:target:*:*", - Vulnerable: true, - }, - { - Criteria: "cpe:2.3:a:vendorB:product:2.2.0:*:*:*:*:target:*:*", - Vulnerable: true, - }, - }, - Operator: "OR", - }, - }, - expected: newUniquePkgTrackerFromSlice( - []pkgCandidate{ - { - Product: "product", - Vendor: "vendorA", - TargetSoftware: "target", - }, - { - Product: "product", - Vendor: "vendorB", - TargetSoftware: "target", - }, - }), - }, - { - name: "de-duplicate-case", - nodes: []nvd.Node{ - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:3.3.3:A:B:C:D:target:E:F", - Vulnerable: true, - }, - { - Criteria: "cpe:2.3:a:vendor:product:2.2.0:Q:R:S:T:target:U:V", - Vulnerable: true, - }, - }, - Operator: "OR", - }, - }, - expected: newUniquePkgTrackerFromSlice( - []pkgCandidate{ - { - Product: "product", - Vendor: "vendor", - TargetSoftware: "target", - }, - }), - }, - { - name: "duplicate-from-nested-nodes", - nodes: []nvd.Node{ - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendorB:product:2.2.0:*:*:*:*:target:*:*", - Vulnerable: true, - }, - }, - Operator: "OR", - }, - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendorA:product:2.2.0:*:*:*:*:target:*:*", - Vulnerable: true, - }, - }, - Operator: "OR", - }, - }, - expected: newUniquePkgTrackerFromSlice( - []pkgCandidate{ - { - Product: "product", - Vendor: "vendorA", - TargetSoftware: "target", - }, - { - Product: "product", - Vendor: "vendorB", - TargetSoftware: "target", - }, - }), - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - actual := findUniquePkgs(nvd.Configuration{Nodes: test.nodes}) - missing, extra := test.expected.Diff(actual) - if len(missing) != 0 { - for _, c := range missing { - t.Errorf("missing candidate: %+v", c) - } - } - - if len(extra) != 0 { - for _, c := range extra { - t.Errorf("extra candidate: %+v", c) - } - } - }) - } - -} - -func strRef(s string) *string { - return &s -} - -func TestBuildConstraints(t *testing.T) { - tests := []struct { - name string - matches []nvd.CpeMatch - expected string - }{ - { - name: "Equals", - matches: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:2.2.0:*:*:*:*:target:*:*", - }, - }, - expected: "= 2.2.0", - }, - { - name: "VersionEndExcluding", - matches: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:*:*:*:*:*:target:*:*", - VersionEndExcluding: strRef("2.3.0"), - }, - }, - expected: "< 2.3.0", - }, - { - name: "VersionEndIncluding", - matches: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:*:*:*:*:*:target:*:*", - VersionEndIncluding: strRef("2.3.0"), - }, - }, - expected: "<= 2.3.0", - }, - { - name: "VersionStartExcluding", - matches: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:*:*:*:*:*:target:*:*", - VersionStartExcluding: strRef("2.3.0"), - }, - }, - expected: "> 2.3.0", - }, - { - name: "VersionStartIncluding", - matches: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:*:*:*:*:*:target:*:*", - VersionStartIncluding: strRef("2.3.0"), - }, - }, - expected: ">= 2.3.0", - }, - { - name: "Version Range", - matches: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:*:*:*:*:*:target:*:*", - VersionStartIncluding: strRef("2.3.0"), - VersionEndIncluding: strRef("2.5.0"), - }, - }, - expected: ">= 2.3.0, <= 2.5.0", - }, - { - name: "Multiple Version Ranges", - matches: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:*:*:*:*:*:target:*:*", - VersionStartIncluding: strRef("2.3.0"), - VersionEndIncluding: strRef("2.5.0"), - }, - { - Criteria: "cpe:2.3:a:vendor:product:*:*:*:*:*:target:*:*", - VersionStartExcluding: strRef("3.3.0"), - VersionEndExcluding: strRef("3.5.0"), - }, - }, - expected: ">= 2.3.0, <= 2.5.0 || > 3.3.0, < 3.5.0", - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - actual := buildConstraints(test.matches) - - if actual != test.expected { - dmp := diffmatchpatch.New() - diffs := dmp.DiffMain(actual, test.expected, true) - t.Errorf("Expected: '%s'", test.expected) - t.Errorf("Got : '%s'", actual) - t.Errorf("Diff : '%s'", dmp.DiffPrettyText(diffs)) - } - }) - } - -} diff --git a/pkg/process/v3/transformers/nvd/unique_pkg_tracker.go b/pkg/process/v3/transformers/nvd/unique_pkg_tracker.go deleted file mode 100644 index 2b7e405d..00000000 --- a/pkg/process/v3/transformers/nvd/unique_pkg_tracker.go +++ /dev/null @@ -1,64 +0,0 @@ -package nvd - -import ( - "sort" - - "github.com/anchore/grype-db/pkg/provider/unmarshal/nvd" -) - -type uniquePkgTracker map[pkgCandidate][]nvd.CpeMatch - -func newUniquePkgTracker() uniquePkgTracker { - return make(uniquePkgTracker) -} - -func (s uniquePkgTracker) Diff(other uniquePkgTracker) (missing []pkgCandidate, extra []pkgCandidate) { - for k := range s { - if !other.Contains(k) { - missing = append(missing, k) - } - } - - for k := range other { - if !s.Contains(k) { - extra = append(extra, k) - } - } - - return -} - -func (s uniquePkgTracker) Matches(i pkgCandidate) []nvd.CpeMatch { - return s[i] -} - -func (s uniquePkgTracker) Add(i pkgCandidate, match nvd.CpeMatch) { - if _, ok := s[i]; !ok { - s[i] = make([]nvd.CpeMatch, 0) - } - s[i] = append(s[i], match) -} - -func (s uniquePkgTracker) Remove(i pkgCandidate) { - delete(s, i) -} - -func (s uniquePkgTracker) Contains(i pkgCandidate) bool { - _, ok := s[i] - return ok -} - -func (s uniquePkgTracker) All() []pkgCandidate { - res := make([]pkgCandidate, len(s)) - idx := 0 - for k := range s { - res[idx] = k - idx++ - } - - sort.SliceStable(res, func(i, j int) bool { - return res[i].String() < res[j].String() - }) - - return res -} diff --git a/pkg/process/v3/transformers/os/test-fixtures/alpine-3.9.json b/pkg/process/v3/transformers/os/test-fixtures/alpine-3.9.json deleted file mode 100644 index b9d84395..00000000 --- a/pkg/process/v3/transformers/os/test-fixtures/alpine-3.9.json +++ /dev/null @@ -1,28 +0,0 @@ -[ - { - "Vulnerability": { - "CVSS": [], - "Description": "", - "FixedIn": [ - { - "Name": "xen", - "NamespaceName": "alpine:3.9", - "Version": "4.11.1-r0", - "VersionFormat": "apk" - } - ], - "Link": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-19967", - "Metadata": { - "NVD": { - "CVSSv2": { - "Score": 4.9, - "Vectors": "AV:L/AC:L/Au:N/C:N/I:N/A:C" - } - } - }, - "Name": "CVE-2018-19967", - "NamespaceName": "alpine:3.9", - "Severity": "Medium" - } - } -] \ No newline at end of file diff --git a/pkg/process/v3/transformers/os/test-fixtures/amazon-multiple-kernel-advisories.json b/pkg/process/v3/transformers/os/test-fixtures/amazon-multiple-kernel-advisories.json deleted file mode 100644 index 82f2b45b..00000000 --- a/pkg/process/v3/transformers/os/test-fixtures/amazon-multiple-kernel-advisories.json +++ /dev/null @@ -1,104 +0,0 @@ -[ - { - "Vulnerability": { - "Name": "ALAS-2021-1704", - "NamespaceName": "amzn:2", - "Description": "", - "Severity": "Medium", - "Metadata": { - "CVE": [ - { - "Name": "CVE-2021-3653" - }, - { - "Name": "CVE-2021-3656" - }, - { - "Name": "CVE-2021-3732" - } - ] - }, - "Link": "https://alas.aws.amazon.com/AL2/ALAS-2021-1704.html", - "FixedIn": [ - { - "Name": "kernel-headers", - "NamespaceName": "amzn:2", - "VersionFormat": "rpm", - "Version": "4.14.246-187.474.amzn2" - }, - { - "Name": "kernel", - "NamespaceName": "amzn:2", - "VersionFormat": "rpm", - "Version": "4.14.246-187.474.amzn2" - } - ] - } - }, - { - "Vulnerability": { - "Name": "ALASKERNEL-5.4-2022-007", - "NamespaceName": "amzn:2", - "Description": "", - "Severity": "Medium", - "Metadata": { - "CVE": [ - { - "Name": "CVE-2021-3753" - }, - { - "Name": "CVE-2021-40490" - } - ] - }, - "Link": "https://alas.aws.amazon.com/AL2/ALASKERNEL-5.4-2022-007.html", - "FixedIn": [ - { - "Name": "kernel-headers", - "NamespaceName": "amzn:2", - "VersionFormat": "rpm", - "Version": "5.4.144-69.257.amzn2" - }, - { - "Name": "kernel", - "NamespaceName": "amzn:2", - "VersionFormat": "rpm", - "Version": "5.4.144-69.257.amzn2" - } - ] - } - }, - { - "Vulnerability": { - "Name": "ALASKERNEL-5.10-2022-005", - "NamespaceName": "amzn:2", - "Description": "", - "Severity": "Medium", - "Metadata": { - "CVE": [ - { - "Name": "CVE-2021-3753" - }, - { - "Name": "CVE-2021-40490" - } - ] - }, - "Link": "https://alas.aws.amazon.com/AL2/ALASKERNEL-5.10-2022-005.html", - "FixedIn": [ - { - "Name": "kernel-headers", - "NamespaceName": "amzn:2", - "VersionFormat": "rpm", - "Version": "5.10.62-55.141.amzn2" - }, - { - "Name": "kernel", - "NamespaceName": "amzn:2", - "VersionFormat": "rpm", - "Version": "5.10.62-55.141.amzn2" - } - ] - } - } -] \ No newline at end of file diff --git a/pkg/process/v3/transformers/os/test-fixtures/amzn.json b/pkg/process/v3/transformers/os/test-fixtures/amzn.json deleted file mode 100644 index a862c32e..00000000 --- a/pkg/process/v3/transformers/os/test-fixtures/amzn.json +++ /dev/null @@ -1,49 +0,0 @@ -[ - { - "Vulnerability": { - "Description": "", - "FixedIn": [ - { - "Name": "389-ds-base", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - }, - { - "Name": "389-ds-base-debuginfo", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - }, - { - "Name": "389-ds-base-devel", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - }, - { - "Name": "389-ds-base-libs", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - }, - { - "Name": "389-ds-base-snmp", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - } - ], - "Link": "https://alas.aws.amazon.com/AL2/ALAS-2018-1106.html", - "Metadata": { - "CVE": [ - - {"Name": "CVE-2018-14648"} - ] - }, - "Name": "ALAS-2018-1106", - "NamespaceName": "amzn:2", - "Severity": "Medium" - } - } -] \ No newline at end of file diff --git a/pkg/process/v3/transformers/os/test-fixtures/debian-8-multiple-entries-for-same-package.json b/pkg/process/v3/transformers/os/test-fixtures/debian-8-multiple-entries-for-same-package.json deleted file mode 100644 index 5025b56e..00000000 --- a/pkg/process/v3/transformers/os/test-fixtures/debian-8-multiple-entries-for-same-package.json +++ /dev/null @@ -1,62 +0,0 @@ -[ - { - "Vulnerability": { - "CVSS": [], - "Description": "", - "FixedIn": [ - { - "Name": "rsyslog", - "NamespaceName": "debian:8", - "VendorAdvisory": { - "AdvisorySummary": [], - "NoAdvisory": false - }, - "Version": "5.7.4-1", - "VersionFormat": "dpkg" - } - ], - "Link": "https://security-tracker.debian.org/tracker/CVE-2011-4623", - "Metadata": { - "NVD": { - "CVSSv2": { - "Score": 2.1, - "Vectors": "AV:L/AC:L/Au:N/C:N/I:N/A:P" - } - } - }, - "Name": "CVE-2011-4623", - "NamespaceName": "debian:8", - "Severity": "Low" - } - }, - { - "Vulnerability": { - "CVSS": [], - "Description": "", - "FixedIn": [ - { - "Name": "rsyslog", - "NamespaceName": "debian:8", - "VendorAdvisory": { - "AdvisorySummary": [], - "NoAdvisory": false - }, - "Version": "3.18.6-1", - "VersionFormat": "dpkg" - } - ], - "Link": "https://security-tracker.debian.org/tracker/CVE-2008-5618", - "Metadata": { - "NVD": { - "CVSSv2": { - "Score": 5, - "Vectors": "AV:N/AC:L/Au:N/C:N/I:N/A:P" - } - } - }, - "Name": "CVE-2008-5618", - "NamespaceName": "debian:8", - "Severity": "Low" - } - } -] \ No newline at end of file diff --git a/pkg/process/v3/transformers/os/test-fixtures/debian-8.json b/pkg/process/v3/transformers/os/test-fixtures/debian-8.json deleted file mode 100644 index a758f13c..00000000 --- a/pkg/process/v3/transformers/os/test-fixtures/debian-8.json +++ /dev/null @@ -1,62 +0,0 @@ -[ - { - "Vulnerability": { - "CVSS": [], - "Description": "", - "FixedIn": [ - { - "Name": "asterisk", - "NamespaceName": "debian:8", - "VendorAdvisory": { - "AdvisorySummary": [], - "NoAdvisory": false - }, - "Version": "1:1.6.2.0~rc3-1", - "VersionFormat": "dpkg" - }, - { - "Name": "auth2db", - "NamespaceName": "debian:8", - "VendorAdvisory": { - "AdvisorySummary": [], - "NoAdvisory": false - }, - "Version": "0.2.5-2+dfsg-1", - "VersionFormat": "dpkg" - }, - { - "Name": "exaile", - "NamespaceName": "debian:8", - "VendorAdvisory": { - "AdvisorySummary": [], - "NoAdvisory": false - }, - "Version": "0.2.14+debian-2.2", - "VersionFormat": "dpkg" - }, - { - "Name": "wordpress", - "NamespaceName": "debian:8", - "VendorAdvisory": { - "AdvisorySummary": [], - "NoAdvisory": false - }, - "Version": "", - "VersionFormat": "dpkg" - } - ], - "Link": "https://security-tracker.debian.org/tracker/CVE-2008-7220", - "Metadata": { - "NVD": { - "CVSSv2": { - "Score": 7.5, - "Vectors": "AV:N/AC:L/Au:N/C:P/I:P/A:P" - } - } - }, - "Name": "CVE-2008-7220", - "NamespaceName": "debian:8", - "Severity": "High" - } - } -] \ No newline at end of file diff --git a/pkg/process/v3/transformers/os/test-fixtures/ol-8-modules.json b/pkg/process/v3/transformers/os/test-fixtures/ol-8-modules.json deleted file mode 100644 index f1d7372b..00000000 --- a/pkg/process/v3/transformers/os/test-fixtures/ol-8-modules.json +++ /dev/null @@ -1,36 +0,0 @@ -[ - { - "Vulnerability": { - "CVSS": [], - "Description": "A flaw was found in PostgreSQL, where some PostgreSQL extensions did not use the search_path safely in their installation script. This flaw allows an attacker with sufficient privileges to trick an administrator into executing a specially crafted script during the extension's installation or update. The highest threat from this vulnerability is to confidentiality, integrity, as well as system availability.", - "FixedIn": [ - { - "Module": "postgresql:10", - "Name": "postgresql", - "NamespaceName": "ol:8", - "Version": "0:10.14-1.module+el8.2.0+7801+be0fed80", - "VersionFormat": "rpm" - }, - { - "Module": "postgresql:12", - "Name": "postgresql", - "NamespaceName": "ol:8", - "Version": "0:12.5-1.module+el8.3.0+9042+664538f4", - "VersionFormat": "rpm" - }, - { - "Module": "postgresql:9.6", - "Name": "postgresql", - "NamespaceName": "ol:8", - "Version": "0:9.6.20-1.module+el8.3.0+8938+7f0e88b6", - "VersionFormat": "rpm" - } - ], - "Link": "https://access.redhat.com/security/cve/CVE-2020-14350", - "Metadata": {}, - "Name": "CVE-2020-14350", - "NamespaceName": "ol:8", - "Severity": "Medium" - } - } -] \ No newline at end of file diff --git a/pkg/process/v3/transformers/os/test-fixtures/ol-8.json b/pkg/process/v3/transformers/os/test-fixtures/ol-8.json deleted file mode 100644 index 09439ece..00000000 --- a/pkg/process/v3/transformers/os/test-fixtures/ol-8.json +++ /dev/null @@ -1,42 +0,0 @@ -[ - { - "Vulnerability": { - "CVSS": [], - "Description": "", - "FixedIn": [ - { - "Name": "libexif", - "NamespaceName": "ol:8", - "Version": "0:0.6.21-17.el8_2", - "VersionFormat": "rpm" - }, - { - "Name": "libexif-devel", - "NamespaceName": "ol:8", - "Version": "0:0.6.21-17.el8_2", - "VersionFormat": "rpm" - }, - { - "Name": "libexif-dummy", - "NamespaceName": "ol:8", - "Version": "None", - "VersionFormat": "rpm" - } - ], - "Link": "http://linux.oracle.com/errata/ELSA-2020-2550.html", - "Metadata": { - "CVE": [ - { - "Link": "http://linux.oracle.com/cve/CVE-2020-13112.html", - "Name": "CVE-2020-13112" - } - ], - "Issued": "2020-06-15", - "RefId": "ELSA-2020-2550" - }, - "Name": "ELSA-2020-2550", - "NamespaceName": "ol:8", - "Severity": "Medium" - } - } -] \ No newline at end of file diff --git a/pkg/process/v3/transformers/os/test-fixtures/rhel-8-modules.json b/pkg/process/v3/transformers/os/test-fixtures/rhel-8-modules.json deleted file mode 100644 index c0400ad5..00000000 --- a/pkg/process/v3/transformers/os/test-fixtures/rhel-8-modules.json +++ /dev/null @@ -1,75 +0,0 @@ -[ - { - "Vulnerability": { - "CVSS": [ - { - "base_metrics": { - "base_score": 7.1, - "base_severity": "High", - "exploitability_score": 1.2, - "impact_score": 5.9 - }, - "status": "verified", - "vector_string": "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:H", - "version": "3.1" - } - ], - "Description": "A flaw was found in PostgreSQL, where some PostgreSQL extensions did not use the search_path safely in their installation script. This flaw allows an attacker with sufficient privileges to trick an administrator into executing a specially crafted script during the extension's installation or update. The highest threat from this vulnerability is to confidentiality, integrity, as well as system availability.", - "FixedIn": [ - { - "Module": "postgresql:10", - "Name": "postgresql", - "NamespaceName": "rhel:8", - "VendorAdvisory": { - "AdvisorySummary": [ - { - "ID": "RHSA-2020:3669", - "Link": "https://access.redhat.com/errata/RHSA-2020:3669" - } - ], - "NoAdvisory": false - }, - "Version": "0:10.14-1.module+el8.2.0+7801+be0fed80", - "VersionFormat": "rpm" - }, - { - "Module": "postgresql:12", - "Name": "postgresql", - "NamespaceName": "rhel:8", - "VendorAdvisory": { - "AdvisorySummary": [ - { - "ID": "RHSA-2020:5620", - "Link": "https://access.redhat.com/errata/RHSA-2020:5620" - } - ], - "NoAdvisory": false - }, - "Version": "0:12.5-1.module+el8.3.0+9042+664538f4", - "VersionFormat": "rpm" - }, - { - "Module": "postgresql:9.6", - "Name": "postgresql", - "NamespaceName": "rhel:8", - "VendorAdvisory": { - "AdvisorySummary": [ - { - "ID": "RHSA-2020:5619", - "Link": "https://access.redhat.com/errata/RHSA-2020:5619" - } - ], - "NoAdvisory": false - }, - "Version": "0:9.6.20-1.module+el8.3.0+8938+7f0e88b6", - "VersionFormat": "rpm" - } - ], - "Link": "https://access.redhat.com/security/cve/CVE-2020-14350", - "Metadata": {}, - "Name": "CVE-2020-14350", - "NamespaceName": "rhel:8", - "Severity": "Medium" - } - } -] \ No newline at end of file diff --git a/pkg/process/v3/transformers/os/test-fixtures/rhel-8.json b/pkg/process/v3/transformers/os/test-fixtures/rhel-8.json deleted file mode 100644 index 2779708c..00000000 --- a/pkg/process/v3/transformers/os/test-fixtures/rhel-8.json +++ /dev/null @@ -1,57 +0,0 @@ -[ - { - "Vulnerability": { - "CVSS": [ - { - "base_metrics": { - "base_score": 8.8, - "base_severity": "High", - "exploitability_score": 2.8, - "impact_score": 5.9 - }, - "status": "verified", - "vector_string": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - "version": "3.1" - } - ], - "Description": "A flaw was found in Mozilla Firefox. A race condition can occur while running the nsDocShell destructor causing a use-after-free memory issue. The highest threat from this vulnerability is to data confidentiality and integrity as well as system availability.", - "FixedIn": [ - { - "Name": "firefox", - "NamespaceName": "rhel:8", - "VendorAdvisory": { - "AdvisorySummary": [ - { - "ID": "RHSA-2020:1341", - "Link": "https://access.redhat.com/errata/RHSA-2020:1341" - } - ], - "NoAdvisory": false - }, - "Version": "0:68.6.1-1.el8_1", - "VersionFormat": "rpm" - }, - { - "Name": "thunderbird", - "NamespaceName": "rhel:8", - "VendorAdvisory": { - "AdvisorySummary": [ - { - "ID": "RHSA-2020:1495", - "Link": "https://access.redhat.com/errata/RHSA-2020:1495" - } - ], - "NoAdvisory": false - }, - "Version": "0:68.7.0-1.el8_1", - "VersionFormat": "rpm" - } - ], - "Link": "https://access.redhat.com/security/cve/CVE-2020-6819", - "Metadata": {}, - "Name": "CVE-2020-6819", - "NamespaceName": "rhel:8", - "Severity": "Critical" - } - } -] \ No newline at end of file diff --git a/pkg/process/v3/transformers/os/test-fixtures/unmarshal-test.json b/pkg/process/v3/transformers/os/test-fixtures/unmarshal-test.json deleted file mode 100644 index edc6d25b..00000000 --- a/pkg/process/v3/transformers/os/test-fixtures/unmarshal-test.json +++ /dev/null @@ -1,104 +0,0 @@ -[ - { - "Vulnerability": { - "Description": "", - "FixedIn": [ - { - "Name": "389-ds-base", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - }, - { - "Name": "389-ds-base-debuginfo", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - }, - { - "Name": "389-ds-base-devel", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - }, - { - "Name": "389-ds-base-libs", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - }, - { - "Name": "389-ds-base-snmp", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - } - ], - "Link": "https://alas.aws.amazon.com/AL2/ALAS-2018-1106.html", - "Metadata": { - "CVE": [ - {"Name": "CVE-2018-14648"} - ] - }, - "Name": "ALAS-2018-1106", - "NamespaceName": "amzn:2", - "Severity": "Medium" - } - }, - { - "Vulnerability": { - "Description": "", - "FixedIn": [ - { - "Name": "kernel-livepatch-4.14.173-137.228", - "NamespaceName": "amzn:2", - "Version": "1.0-3.amzn2", - "VersionFormat": "rpm" - }, - { - "Name": "kernel-livepatch-4.14.173-137.228-debuginfo", - "NamespaceName": "amzn:2", - "Version": "1.0-3.amzn2", - "VersionFormat": "rpm" - } - ], - "Link": "https://alas.aws.amazon.com/AL2/ALASLIVEPATCH-2020-012.html", - "Metadata": { - "CVE": [ - {"Name": "CVE-2020-12657"} - ] - }, - "Name": "ALASLIVEPATCH-2020-012", - "NamespaceName": "amzn:2", - "Severity": "High" - } - }, - { - "Vulnerability": { - "Description": "", - "FixedIn": [ - { - "Name": "kernel-livepatch-4.14.171-136.231", - "NamespaceName": "amzn:2", - "Version": "1.0-5.amzn2", - "VersionFormat": "rpm" - }, - { - "Name": "kernel-livepatch-4.14.171-136.231-debuginfo", - "NamespaceName": "amzn:2", - "Version": "1.0-5.amzn2", - "VersionFormat": "rpm" - } - ], - "Link": "https://alas.aws.amazon.com/AL2/ALASLIVEPATCH-2020-011.html", - "Metadata": { - "CVE": [ - {"Name": "CVE-2020-12657"} - ] - }, - "Name": "ALASLIVEPATCH-2020-011", - "NamespaceName": "amzn:2", - "Severity": "High" - } - } -] \ No newline at end of file diff --git a/pkg/process/v3/transformers/os/transform.go b/pkg/process/v3/transformers/os/transform.go deleted file mode 100644 index 6caffd18..00000000 --- a/pkg/process/v3/transformers/os/transform.go +++ /dev/null @@ -1,182 +0,0 @@ -package os - -import ( - "fmt" - "strings" - - "github.com/anchore/grype-db/pkg/data" - "github.com/anchore/grype-db/pkg/process/internal/common" - "github.com/anchore/grype-db/pkg/process/v3/transformers" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v3" -) - -const ( - // TODO: tech debt from a previous design - feed = "vulnerabilities" -) - -func Transform(vulnerability unmarshal.OSVulnerability) ([]data.Entry, error) { - group := vulnerability.Vulnerability.NamespaceName - - var allVulns []grypeDB.Vulnerability - - recordSource := grypeDB.RecordSource(feed, group) - entryNamespace, err := grypeDB.NamespaceForFeedGroup(feed, group) - if err != nil { - return nil, err - } - - vulnerability.Vulnerability.FixedIn = vulnerability.Vulnerability.FixedIn.FilterToHighestModularity() - - // there may be multiple packages indicated within the FixedIn field, we should make - // separate vulnerability entries (one for each name|namespace combo) while merging - // constraint ranges as they are found. - for idx, fixedInEntry := range vulnerability.Vulnerability.FixedIn { - // create vulnerability entry - allVulns = append(allVulns, grypeDB.Vulnerability{ - ID: vulnerability.Vulnerability.Name, - VersionConstraint: enforceConstraint(fixedInEntry.Version, fixedInEntry.VersionFormat, vulnerability.Vulnerability.Name), - VersionFormat: fixedInEntry.VersionFormat, - PackageName: fixedInEntry.Name, - Namespace: entryNamespace, - RelatedVulnerabilities: getRelatedVulnerabilities(vulnerability), - Fix: getFix(vulnerability, idx), - Advisories: getAdvisories(vulnerability, idx), - }) - } - - // create vulnerability metadata entry (a single entry keyed off of the vulnerability ID) - metadata := grypeDB.VulnerabilityMetadata{ - ID: vulnerability.Vulnerability.Name, - Namespace: entryNamespace, - DataSource: vulnerability.Vulnerability.Link, - RecordSource: recordSource, - Severity: vulnerability.Vulnerability.Severity, - URLs: getLinks(vulnerability), - Description: vulnerability.Vulnerability.Description, - Cvss: getCvss(vulnerability), - } - - return transformers.NewEntries(allVulns, metadata), nil -} - -func getLinks(entry unmarshal.OSVulnerability) []string { - // find all URLs related to the vulnerability - links := []string{entry.Vulnerability.Link} - if entry.Vulnerability.Metadata.CVE != nil { - for _, cve := range entry.Vulnerability.Metadata.CVE { - if cve.Link != "" { - links = append(links, cve.Link) - } - } - } - return links -} - -func getCvss(entry unmarshal.OSVulnerability) (cvss []grypeDB.Cvss) { - for _, vendorCvss := range entry.Vulnerability.CVSS { - cvss = append(cvss, grypeDB.Cvss{ - Version: vendorCvss.Version, - Vector: vendorCvss.VectorString, - Metrics: grypeDB.NewCvssMetrics( - vendorCvss.BaseMetrics.BaseScore, - vendorCvss.BaseMetrics.ExploitabilityScore, - vendorCvss.BaseMetrics.ImpactScore, - ), - VendorMetadata: transformers.VendorBaseMetrics{ - BaseSeverity: vendorCvss.BaseMetrics.BaseSeverity, - Status: vendorCvss.Status, - }, - }) - } - return cvss -} - -func getAdvisories(entry unmarshal.OSVulnerability, idx int) (advisories []grypeDB.Advisory) { - fixedInEntry := entry.Vulnerability.FixedIn[idx] - - for _, advisory := range fixedInEntry.VendorAdvisory.AdvisorySummary { - advisories = append(advisories, grypeDB.Advisory{ - ID: advisory.ID, - Link: advisory.Link, - }) - } - return advisories -} - -func getFix(entry unmarshal.OSVulnerability, idx int) grypeDB.Fix { - fixedInEntry := entry.Vulnerability.FixedIn[idx] - - var fixedInVersions []string - fixedInVersion := common.CleanFixedInVersion(fixedInEntry.Version) - if fixedInVersion != "" { - fixedInVersions = append(fixedInVersions, fixedInVersion) - } - - fixState := grypeDB.NotFixedState - if len(fixedInVersions) > 0 { - fixState = grypeDB.FixedState - } else if fixedInEntry.VendorAdvisory.NoAdvisory { - fixState = grypeDB.WontFixState - } - - return grypeDB.Fix{ - Versions: fixedInVersions, - State: fixState, - } -} - -func getRelatedVulnerabilities(entry unmarshal.OSVulnerability) (vulns []grypeDB.VulnerabilityReference) { - // associate related vulnerabilities from the NVD namespace - if strings.HasPrefix(entry.Vulnerability.Name, "CVE") { - vulns = append(vulns, grypeDB.VulnerabilityReference{ - ID: entry.Vulnerability.Name, - Namespace: grypeDB.NVDNamespace, - }) - } - - // note: an example of multiple CVEs for a record is centos:5 RHSA-2007:0055 which maps to CVE-2007-0002 and CVE-2007-1466 - for _, ref := range entry.Vulnerability.Metadata.CVE { - vulns = append(vulns, grypeDB.VulnerabilityReference{ - ID: ref.Name, - Namespace: grypeDB.NVDNamespace, - }) - } - return vulns -} - -func deriveConstraintFromFix(fixVersion, vulnerabilityID string) string { - constraint := fmt.Sprintf("< %s", fixVersion) - - if strings.HasPrefix(vulnerabilityID, "ALASKERNEL-") { - // Amazon advisories of the form ALASKERNEL-5.4-2023-048 should be interpreted as only applying to - // the 5.4.x kernel line since Amazon issue a separate advisory per affected line, thus the constraint - // should be >= 5.4, < {fix version}. In the future the vunnel schema for OS vulns should be enhanced - // to emit actual constraints rather than fixed-in entries (tracked in https://github.com/anchore/vunnel/issues/266) - // at which point this workaround in grype-db can be removed. - - components := strings.Split(vulnerabilityID, "-") - - if len(components) == 4 { - base := components[1] - constraint = fmt.Sprintf(">= %s, < %s", base, fixVersion) - } - } - - return constraint -} - -func enforceConstraint(constraint, format, vulnerabilityID string) string { - constraint = common.CleanConstraint(constraint) - if len(constraint) == 0 { - return "" - } - switch strings.ToLower(format) { - case "semver": - return common.EnforceSemVerConstraint(constraint) - default: - // the passed constraint is a fixed version - return deriveConstraintFromFix(constraint, vulnerabilityID) - } -} diff --git a/pkg/process/v3/transformers/os/transform_test.go b/pkg/process/v3/transformers/os/transform_test.go deleted file mode 100644 index aa5e2609..00000000 --- a/pkg/process/v3/transformers/os/transform_test.go +++ /dev/null @@ -1,758 +0,0 @@ -package os - -import ( - "os" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - testUtils "github.com/anchore/grype-db/pkg/process/internal/tests" - "github.com/anchore/grype-db/pkg/process/v3/transformers" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v3" -) - -func TestUnmarshalOSVulnerabilitiesEntries(t *testing.T) { - f, err := os.Open("test-fixtures/unmarshal-test.json") - require.NoError(t, err) - defer testUtils.CloseFile(f) - - entries, err := unmarshal.OSVulnerabilityEntries(f) - require.NoError(t, err) - - assert.Len(t, entries, 3) - -} - -func TestParseVulnerabilitiesEntry(t *testing.T) { - tc := []struct { - name string - numEntries int - fixture string - vulns []grypeDB.Vulnerability - metadata grypeDB.VulnerabilityMetadata - feed, group string - }{ - { - name: "Amazon", - numEntries: 1, - fixture: "test-fixtures/amzn.json", - feed: "vulnerabilities", - group: "amzn:2", - vulns: []grypeDB.Vulnerability{ - { - ID: "ALAS-2018-1106", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2018-14648", - Namespace: grypeDB.NVDNamespace, - }, - }, - PackageName: "389-ds-base", - Namespace: "amzn:2", - Fix: grypeDB.Fix{ - Versions: []string{"1.3.8.4-15.amzn2.0.1"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALAS-2018-1106", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2018-14648", - Namespace: grypeDB.NVDNamespace, - }, - }, - PackageName: "389-ds-base-debuginfo", - Namespace: "amzn:2", - Fix: grypeDB.Fix{ - Versions: []string{"1.3.8.4-15.amzn2.0.1"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALAS-2018-1106", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2018-14648", - Namespace: grypeDB.NVDNamespace, - }, - }, - PackageName: "389-ds-base-devel", - Namespace: "amzn:2", - Fix: grypeDB.Fix{ - Versions: []string{"1.3.8.4-15.amzn2.0.1"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALAS-2018-1106", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2018-14648", - Namespace: grypeDB.NVDNamespace, - }, - }, - PackageName: "389-ds-base-libs", - Namespace: "amzn:2", - Fix: grypeDB.Fix{ - Versions: []string{"1.3.8.4-15.amzn2.0.1"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALAS-2018-1106", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2018-14648", - Namespace: grypeDB.NVDNamespace, - }, - }, - PackageName: "389-ds-base-snmp", - Namespace: "amzn:2", - Fix: grypeDB.Fix{ - Versions: []string{"1.3.8.4-15.amzn2.0.1"}, - State: grypeDB.FixedState, - }, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "ALAS-2018-1106", - Namespace: "amzn:2", - DataSource: "https://alas.aws.amazon.com/AL2/ALAS-2018-1106.html", - RecordSource: "vulnerabilities:amzn:2", - Severity: "Medium", - URLs: []string{"https://alas.aws.amazon.com/AL2/ALAS-2018-1106.html"}, - }, - }, - { - name: "Debian", - numEntries: 1, - fixture: "test-fixtures/debian-8.json", - feed: "vulnerabilities", - group: "debian:8", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2008-7220", - PackageName: "asterisk", - VersionConstraint: "< 1:1.6.2.0~rc3-1", - VersionFormat: "dpkg", - Namespace: "debian:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2008-7220", - Namespace: "nvd", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"1:1.6.2.0~rc3-1"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "CVE-2008-7220", - PackageName: "auth2db", - VersionConstraint: "< 0.2.5-2+dfsg-1", - VersionFormat: "dpkg", - Namespace: "debian:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2008-7220", - Namespace: "nvd", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"0.2.5-2+dfsg-1"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "CVE-2008-7220", - PackageName: "exaile", - VersionConstraint: "< 0.2.14+debian-2.2", - VersionFormat: "dpkg", - Namespace: "debian:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2008-7220", - Namespace: "nvd", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"0.2.14+debian-2.2"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "CVE-2008-7220", - PackageName: "wordpress", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2008-7220", - Namespace: "nvd", - }, - }, - Fix: grypeDB.Fix{ - State: grypeDB.NotFixedState, - }, - VersionConstraint: "", - VersionFormat: "dpkg", - Namespace: "debian:8", - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2008-7220", - Namespace: "debian:8", - DataSource: "https://security-tracker.debian.org/tracker/CVE-2008-7220", - RecordSource: "vulnerabilities:debian:8", - Severity: "High", - URLs: []string{"https://security-tracker.debian.org/tracker/CVE-2008-7220"}, - Description: "", - }, - }, - { - name: "RHEL", - numEntries: 1, - fixture: "test-fixtures/rhel-8.json", - feed: "vulnerabilities", - group: "rhel:8", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2020-6819", - PackageName: "firefox", - VersionConstraint: "< 0:68.6.1-1.el8_1", - VersionFormat: "rpm", - Namespace: "rhel:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2020-6819", - Namespace: "nvd", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"0:68.6.1-1.el8_1"}, - State: grypeDB.FixedState, - }, - Advisories: []grypeDB.Advisory{ - { - ID: "RHSA-2020:1341", - Link: "https://access.redhat.com/errata/RHSA-2020:1341", - }, - }, - }, - { - ID: "CVE-2020-6819", - PackageName: "thunderbird", - VersionConstraint: "< 0:68.7.0-1.el8_1", - VersionFormat: "rpm", - Namespace: "rhel:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2020-6819", - Namespace: "nvd", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"0:68.7.0-1.el8_1"}, - State: grypeDB.FixedState, - }, - Advisories: []grypeDB.Advisory{ - { - ID: "RHSA-2020:1495", - Link: "https://access.redhat.com/errata/RHSA-2020:1495", - }, - }, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2020-6819", - DataSource: "https://access.redhat.com/security/cve/CVE-2020-6819", - Namespace: "rhel:8", - RecordSource: "vulnerabilities:rhel:8", - Severity: "Critical", - URLs: []string{"https://access.redhat.com/security/cve/CVE-2020-6819"}, - Description: "A flaw was found in Mozilla Firefox. A race condition can occur while running the nsDocShell destructor causing a use-after-free memory issue. The highest threat from this vulnerability is to data confidentiality and integrity as well as system availability.", - Cvss: []grypeDB.Cvss{ - { - Version: "3.1", - Vector: "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - Metrics: grypeDB.NewCvssMetrics( - 8.8, - 2.8, - 5.9, - ), - VendorMetadata: transformers.VendorBaseMetrics{ - Status: "verified", - BaseSeverity: "High", - }, - }, - }, - }, - }, - { - name: "RHEL with modularity", - numEntries: 1, - fixture: "test-fixtures/rhel-8-modules.json", - feed: "vulnerabilities", - group: "rhel:8", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2020-14350", - PackageName: "postgresql", - VersionConstraint: "< 0:12.5-1.module+el8.3.0+9042+664538f4", - VersionFormat: "rpm", - Namespace: "rhel:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2020-14350", - Namespace: "nvd", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"0:12.5-1.module+el8.3.0+9042+664538f4"}, - State: grypeDB.FixedState, - }, - Advisories: []grypeDB.Advisory{ - { - ID: "RHSA-2020:5620", - Link: "https://access.redhat.com/errata/RHSA-2020:5620", - }, - }, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2020-14350", - DataSource: "https://access.redhat.com/security/cve/CVE-2020-14350", - Namespace: "rhel:8", - RecordSource: "vulnerabilities:rhel:8", - Severity: "Medium", - URLs: []string{"https://access.redhat.com/security/cve/CVE-2020-14350"}, - Description: "A flaw was found in PostgreSQL, where some PostgreSQL extensions did not use the search_path safely in their installation script. This flaw allows an attacker with sufficient privileges to trick an administrator into executing a specially crafted script during the extension's installation or update. The highest threat from this vulnerability is to confidentiality, integrity, as well as system availability.", - Cvss: []grypeDB.Cvss{ - { - Version: "3.1", - Vector: "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:H", - Metrics: grypeDB.NewCvssMetrics( - 7.1, - 1.2, - 5.9, - ), - VendorMetadata: transformers.VendorBaseMetrics{ - Status: "verified", - BaseSeverity: "High", - }, - }, - }, - }, - }, - { - name: "Alpine", - numEntries: 1, - fixture: "test-fixtures/alpine-3.9.json", - feed: "vulnerabilities", - group: "alpine:3.9", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2018-19967", - PackageName: "xen", - VersionConstraint: "< 4.11.1-r0", - VersionFormat: "apk", - Namespace: "alpine:3.9", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2018-19967", - Namespace: "nvd", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"4.11.1-r0"}, - State: grypeDB.FixedState, - }, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2018-19967", - DataSource: "http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-19967", - Namespace: "alpine:3.9", - RecordSource: "vulnerabilities:alpine:3.9", - Severity: "Medium", - URLs: []string{"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-19967"}, - Description: "", - }, - }, - { - name: "Oracle", - numEntries: 1, - fixture: "test-fixtures/ol-8.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "ELSA-2020-2550", - PackageName: "libexif", - VersionConstraint: "< 0:0.6.21-17.el8_2", - VersionFormat: "rpm", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2020-13112", - Namespace: grypeDB.NVDNamespace, - }, - }, - Namespace: "ol:8", - Fix: grypeDB.Fix{ - Versions: []string{"0:0.6.21-17.el8_2"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ELSA-2020-2550", - PackageName: "libexif-devel", - VersionConstraint: "< 0:0.6.21-17.el8_2", - VersionFormat: "rpm", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2020-13112", - Namespace: grypeDB.NVDNamespace, - }, - }, - Namespace: "ol:8", - Fix: grypeDB.Fix{ - Versions: []string{"0:0.6.21-17.el8_2"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ELSA-2020-2550", - PackageName: "libexif-dummy", - VersionConstraint: "", - VersionFormat: "rpm", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2020-13112", - Namespace: grypeDB.NVDNamespace, - }, - }, - Namespace: "ol:8", - Fix: grypeDB.Fix{ - Versions: nil, - State: grypeDB.NotFixedState, - }, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "ELSA-2020-2550", - DataSource: "http://linux.oracle.com/errata/ELSA-2020-2550.html", - Namespace: "ol:8", - RecordSource: "vulnerabilities:ol:8", - Severity: "Medium", - URLs: []string{"http://linux.oracle.com/errata/ELSA-2020-2550.html", "http://linux.oracle.com/cve/CVE-2020-13112.html"}, - }, - }, - { - name: "Oracle Linux 8 with modularity", - numEntries: 1, - fixture: "test-fixtures/ol-8-modules.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2020-14350", - PackageName: "postgresql", - VersionConstraint: "< 0:12.5-1.module+el8.3.0+9042+664538f4", - VersionFormat: "rpm", - Namespace: "ol:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2020-14350", - Namespace: "nvd", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"0:12.5-1.module+el8.3.0+9042+664538f4"}, - State: grypeDB.FixedState, - }, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2020-14350", - DataSource: "https://access.redhat.com/security/cve/CVE-2020-14350", - Namespace: "ol:8", - RecordSource: "vulnerabilities:ol:8", - Severity: "Medium", - URLs: []string{"https://access.redhat.com/security/cve/CVE-2020-14350"}, - Description: "A flaw was found in PostgreSQL, where some PostgreSQL extensions did not use the search_path safely in their installation script. This flaw allows an attacker with sufficient privileges to trick an administrator into executing a specially crafted script during the extension's installation or update. The highest threat from this vulnerability is to confidentiality, integrity, as well as system availability.", - }, - }, - } - - for _, test := range tc { - t.Run(test.name, func(t *testing.T) { - f, err := os.Open(test.fixture) - require.NoError(t, err) - t.Cleanup(func() { - assert.NoError(t, f.Close()) - }) - - entries, err := unmarshal.OSVulnerabilityEntries(f) - require.NoError(t, err) - require.Len(t, entries, 1) - - entry := entries[0] - - dataEntries, err := Transform(entry) - require.NoError(t, err) - - var vulns []grypeDB.Vulnerability - for _, entry := range dataEntries { - switch vuln := entry.Data.(type) { - case grypeDB.Vulnerability: - vulns = append(vulns, vuln) - case grypeDB.VulnerabilityMetadata: - assert.Equal(t, test.metadata, vuln) - default: - t.Fatalf("unexpected condition: data entry does not have a vulnerability or a metadata") - } - } - - if diff := cmp.Diff(test.vulns, vulns); diff != "" { - t.Errorf("vulnerabilities do not match (-want +got):\n%s", diff) - } - - }) - } - -} - -func TestParseVulnerabilitiesAllEntries(t *testing.T) { - tests := []struct { - name string - numEntries int - fixture string - vulns []grypeDB.Vulnerability - }{ - { - name: "Debian", - numEntries: 2, - fixture: "test-fixtures/debian-8-multiple-entries-for-same-package.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2011-4623", - PackageName: "rsyslog", - VersionConstraint: "< 5.7.4-1", - VersionFormat: "dpkg", - Namespace: "debian:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2011-4623", - Namespace: "nvd", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"5.7.4-1"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "CVE-2008-5618", - PackageName: "rsyslog", - VersionConstraint: "< 3.18.6-1", - VersionFormat: "dpkg", - Namespace: "debian:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2008-5618", - Namespace: "nvd", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"3.18.6-1"}, - State: grypeDB.FixedState, - }, - }, - }, - }, - { - name: "Amazon", - numEntries: 3, - fixture: "test-fixtures/amazon-multiple-kernel-advisories.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "ALAS-2021-1704", - PackageName: "kernel-headers", - VersionConstraint: "< 4.14.246-187.474.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2021-3653", - Namespace: "nvd", - }, - { - ID: "CVE-2021-3656", - Namespace: "nvd", - }, - { - ID: "CVE-2021-3732", - Namespace: "nvd", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"4.14.246-187.474.amzn2"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALAS-2021-1704", - PackageName: "kernel", - VersionConstraint: "< 4.14.246-187.474.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2021-3653", - Namespace: "nvd", - }, - { - ID: "CVE-2021-3656", - Namespace: "nvd", - }, - { - ID: "CVE-2021-3732", - Namespace: "nvd", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"4.14.246-187.474.amzn2"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALASKERNEL-5.4-2022-007", - PackageName: "kernel-headers", - VersionConstraint: ">= 5.4, < 5.4.144-69.257.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2021-3753", - Namespace: "nvd", - }, - { - ID: "CVE-2021-40490", - Namespace: "nvd", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"5.4.144-69.257.amzn2"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALASKERNEL-5.4-2022-007", - PackageName: "kernel", - VersionConstraint: ">= 5.4, < 5.4.144-69.257.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2021-3753", - Namespace: "nvd", - }, - { - ID: "CVE-2021-40490", - Namespace: "nvd", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"5.4.144-69.257.amzn2"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALASKERNEL-5.10-2022-005", - PackageName: "kernel-headers", - VersionConstraint: ">= 5.10, < 5.10.62-55.141.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2021-3753", - Namespace: "nvd", - }, - { - ID: "CVE-2021-40490", - Namespace: "nvd", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"5.10.62-55.141.amzn2"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALASKERNEL-5.10-2022-005", - PackageName: "kernel", - VersionConstraint: ">= 5.10, < 5.10.62-55.141.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2021-3753", - Namespace: "nvd", - }, - { - ID: "CVE-2021-40490", - Namespace: "nvd", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"5.10.62-55.141.amzn2"}, - State: grypeDB.FixedState, - }, - }, - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - f, err := os.Open(test.fixture) - require.NoError(t, err) - t.Cleanup(func() { - assert.NoError(t, f.Close()) - }) - - entries, err := unmarshal.OSVulnerabilityEntries(f) - require.NoError(t, err) - require.Len(t, entries, test.numEntries) - - var vulns []grypeDB.Vulnerability - for _, entry := range entries { - dataEntries, err := Transform(entry) - require.NoError(t, err) - - for _, entry := range dataEntries { - switch vuln := entry.Data.(type) { - case grypeDB.Vulnerability: - vulns = append(vulns, vuln) - case grypeDB.VulnerabilityMetadata: - default: - t.Fatalf("unexpected condition: data entry does not have a vulnerability or a metadata") - } - } - } - - if diff := cmp.Diff(test.vulns, vulns); diff != "" { - t.Errorf("vulnerabilities do not match (-want +got):\n%s", diff) - } - }) - } -} diff --git a/pkg/process/v3/transformers/vulnerability_metadata.go b/pkg/process/v3/transformers/vulnerability_metadata.go deleted file mode 100644 index da214315..00000000 --- a/pkg/process/v3/transformers/vulnerability_metadata.go +++ /dev/null @@ -1,8 +0,0 @@ -package transformers - -// VendorBaseMetrics captures extra metrics that do not fit into a common CVSS -// struct, like Status and BaseSeverity -type VendorBaseMetrics struct { - BaseSeverity string - Status string -} diff --git a/pkg/process/v3/writer.go b/pkg/process/v3/writer.go deleted file mode 100644 index f649491e..00000000 --- a/pkg/process/v3/writer.go +++ /dev/null @@ -1,132 +0,0 @@ -package v3 - -import ( - "crypto/sha256" - "fmt" - "path" - "path/filepath" - "strings" - "time" - - "github.com/spf13/afero" - - "github.com/anchore/grype-db/internal/file" - "github.com/anchore/grype-db/internal/log" - "github.com/anchore/grype-db/pkg/data" - "github.com/anchore/grype/grype/db/legacy/distribution" - grypeDB "github.com/anchore/grype/grype/db/v3" - grypeDBStore "github.com/anchore/grype/grype/db/v3/store" -) - -var _ data.Writer = (*writer)(nil) - -type writer struct { - dbPath string - store grypeDB.Store -} - -func NewWriter(directory string, dataAge time.Time) (data.Writer, error) { - dbPath := path.Join(directory, grypeDB.VulnerabilityStoreFileName) - theStore, err := grypeDBStore.New(dbPath, true) - if err != nil { - return nil, fmt.Errorf("unable to create writer: %w", err) - } - - if err := theStore.SetID(grypeDB.NewID(dataAge)); err != nil { - return nil, fmt.Errorf("unable to set DB ID: %w", err) - } - - return &writer{ - dbPath: dbPath, - store: theStore, - }, nil -} - -func (w writer) Write(entries ...data.Entry) error { - for _, entry := range entries { - if entry.DBSchemaVersion != grypeDB.SchemaVersion { - return fmt.Errorf("wrong schema version: want %+v got %+v", grypeDB.SchemaVersion, entry.DBSchemaVersion) - } - - switch row := entry.Data.(type) { - case grypeDB.Vulnerability: - if err := w.store.AddVulnerability(row); err != nil { - return fmt.Errorf("unable to write vulnerability to store: %w", err) - } - case grypeDB.VulnerabilityMetadata: - normalizeSeverity(&row, w.store) - if err := w.store.AddVulnerabilityMetadata(row); err != nil { - return fmt.Errorf("unable to write vulnerability metadata to store: %w", err) - } - default: - return fmt.Errorf("data entry does not have a vulnerability or a metadata: %T", row) - } - } - - return nil -} - -func (w writer) metadata() (*distribution.Metadata, error) { - hashStr, err := file.ContentDigest(afero.NewOsFs(), w.dbPath, sha256.New()) - if err != nil { - return nil, fmt.Errorf("failed to hash database file (%s): %w", w.dbPath, err) - } - - storeID, err := w.store.GetID() - if err != nil { - return nil, fmt.Errorf("failed to fetch store ID: %w", err) - } - - metadata := distribution.Metadata{ - Built: storeID.BuildTimestamp, - Version: storeID.SchemaVersion, - Checksum: "sha256:" + hashStr, - } - return &metadata, nil -} - -func (w writer) Close() error { - w.store.Close() - metadata, err := w.metadata() - if err != nil { - return err - } - - metadataPath := path.Join(filepath.Dir(w.dbPath), distribution.MetadataFileName) - if err = metadata.Write(metadataPath); err != nil { - return err - } - - log.WithFields("path", w.dbPath).Info("database created") - log.WithFields("path", metadataPath).Debug("database metadata created") - - return nil -} - -func normalizeSeverity(metadata *grypeDB.VulnerabilityMetadata, reader grypeDB.VulnerabilityMetadataStoreReader) { - metadata.Severity = string(data.ParseSeverity(metadata.Severity)) - if metadata.Severity != "" && strings.ToLower(metadata.Severity) != "unknown" { - return - } - if !strings.HasPrefix(strings.ToLower(metadata.ID), "cve") { - return - } - if strings.HasPrefix(metadata.Namespace, grypeDB.NVDNamespace) { - return - } - m, err := reader.GetVulnerabilityMetadata(metadata.ID, grypeDB.NVDNamespace) - if err != nil { - log.WithFields("id", metadata.ID, "error", err).Warn("error fetching vulnerability metadata from NVD namespace") - return - } - if m == nil { - log.WithFields("id", metadata.ID).Trace("unable to find vulnerability metadata from NVD namespace") - return - } - - newSeverity := string(data.ParseSeverity(m.Severity)) - if newSeverity != metadata.Severity { - log.WithFields("id", metadata.ID, "namespace", metadata.Namespace, "sev-from", metadata.Severity, "sev-to", newSeverity).Trace("overriding irrelevant severity with data from NVD record") - } - metadata.Severity = newSeverity -} diff --git a/pkg/process/v3/writer_test.go b/pkg/process/v3/writer_test.go deleted file mode 100644 index 7596ca04..00000000 --- a/pkg/process/v3/writer_test.go +++ /dev/null @@ -1,126 +0,0 @@ -package v3 - -import ( - "errors" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/anchore/grype-db/pkg/data" - grypeDB "github.com/anchore/grype/grype/db/v3" -) - -var _ grypeDB.VulnerabilityMetadataStoreReader = (*mockReader)(nil) - -type mockReader struct { - metadata *grypeDB.VulnerabilityMetadata - err error -} - -func newMockReader(sev string) *mockReader { - return &mockReader{ - metadata: &grypeDB.VulnerabilityMetadata{ - Severity: sev, - Namespace: "nvd", - }, - } -} - -func newDeadMockReader() *mockReader { - return &mockReader{ - err: errors.New("dead"), - } -} - -func (m mockReader) GetVulnerabilityMetadata(_, _ string) (*grypeDB.VulnerabilityMetadata, error) { - return m.metadata, m.err -} - -func (m mockReader) GetAllVulnerabilityMetadata() (*[]grypeDB.VulnerabilityMetadata, error) { - panic("implement me") -} - -func Test_normalizeSeverity(t *testing.T) { - - tests := []struct { - name string - initialSeverity string - namespace string - cveID string - reader grypeDB.VulnerabilityMetadataStoreReader - expected data.Severity - }{ - { - name: "missing severity set to Unknown", - initialSeverity: "", - namespace: "test", - reader: &mockReader{}, - expected: data.SeverityUnknown, - }, - { - name: "non-cve records metadata missing severity set to Unknown", - cveID: "GHSA-1234-1234-1234", - initialSeverity: "", - namespace: "test", - reader: newDeadMockReader(), // should not be used - expected: data.SeverityUnknown, - }, - { - name: "non-cve records metadata with severity set should not be overriden", - cveID: "GHSA-1234-1234-1234", - initialSeverity: "high", - namespace: "test", - reader: newMockReader("critical"), // should not be used - expected: data.SeverityHigh, - }, - { - name: "override empty severity from NVD", - initialSeverity: "", - namespace: "test", - reader: newMockReader("low"), - expected: data.SeverityLow, - }, - { - name: "override unknown severity from NVD", - initialSeverity: "unknown", - namespace: "test", - reader: newMockReader("low"), - expected: data.SeverityLow, - }, - { - name: "ignore record with severity already set", - initialSeverity: "Low", - namespace: "test", - reader: newMockReader("critical"), // should not be used - expected: data.SeverityLow, - }, - { - name: "ignore nvd records", - initialSeverity: "Low", - namespace: "nvdv2:cves", - reader: newDeadMockReader(), // should not be used - expected: data.SeverityLow, - }, - { - name: "db errors should not fail or modify the record other than normalizing unset value", - initialSeverity: "", - namespace: "test", - reader: newDeadMockReader(), - expected: data.SeverityUnknown, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - record := &grypeDB.VulnerabilityMetadata{ - ID: "cve-2020-0000", - Severity: tt.initialSeverity, - Namespace: tt.namespace, - } - if tt.cveID != "" { - record.ID = tt.cveID - } - normalizeSeverity(record, tt.reader) - assert.Equal(t, string(tt.expected), record.Severity) - }) - } -} diff --git a/pkg/process/v4/processors.go b/pkg/process/v4/processors.go deleted file mode 100644 index 9e0a69a1..00000000 --- a/pkg/process/v4/processors.go +++ /dev/null @@ -1,21 +0,0 @@ -package v4 - -import ( - "github.com/anchore/grype-db/pkg/data" - "github.com/anchore/grype-db/pkg/process/processors" - "github.com/anchore/grype-db/pkg/process/v4/transformers/github" - "github.com/anchore/grype-db/pkg/process/v4/transformers/matchexclusions" - "github.com/anchore/grype-db/pkg/process/v4/transformers/msrc" - "github.com/anchore/grype-db/pkg/process/v4/transformers/nvd" - "github.com/anchore/grype-db/pkg/process/v4/transformers/os" -) - -func Processors() []data.Processor { - return []data.Processor{ - processors.NewGitHubProcessor(github.Transform), - processors.NewMSRCProcessor(msrc.Transform), - processors.NewNVDProcessor(nvd.Transform), - processors.NewOSProcessor(os.Transform), - processors.NewMatchExclusionProcessor(matchexclusions.Transform), - } -} diff --git a/pkg/process/v4/transformers/entry.go b/pkg/process/v4/transformers/entry.go deleted file mode 100644 index a60d5daf..00000000 --- a/pkg/process/v4/transformers/entry.go +++ /dev/null @@ -1,22 +0,0 @@ -package transformers - -import ( - "github.com/anchore/grype-db/pkg/data" - grypeDB "github.com/anchore/grype/grype/db/v4" -) - -func NewEntries(vs []grypeDB.Vulnerability, metadata grypeDB.VulnerabilityMetadata) []data.Entry { - entries := []data.Entry{ - { - DBSchemaVersion: grypeDB.SchemaVersion, - Data: metadata, - }, - } - for _, vuln := range vs { - entries = append(entries, data.Entry{ - DBSchemaVersion: grypeDB.SchemaVersion, - Data: vuln, - }) - } - return entries -} diff --git a/pkg/process/v4/transformers/github/test-fixtures/github-github-npm-0.json b/pkg/process/v4/transformers/github/test-fixtures/github-github-npm-0.json deleted file mode 100644 index b0a7d1e9..00000000 --- a/pkg/process/v4/transformers/github/test-fixtures/github-github-npm-0.json +++ /dev/null @@ -1,31 +0,0 @@ - -{ - "Advisory": { - "CVE": [ - "CVE-2020-14000" - ], - "FixedIn": [ - { - "ecosystem": "npm", - "identifier": "0.2.0-prerelease.20200714185213", - "name": "scratch-vm", - "namespace": "github:npm", - "range": "<= 0.2.0-prerelease.20200709173451" - } - ], - "Metadata": { - "CVE": [ - "CVE-2020-14000" - ] - }, - "Severity": "High", - "Summary": "Remote Code Execution in scratch-vm", - "ghsaId": "GHSA-vc9j-fhvv-8vrf", - "namespace": "github:npm", - "url": "https://github.com/advisories/GHSA-vc9j-fhvv-8vrf", - "withdrawn": null - }, - "Vulnerability": {} -} - - diff --git a/pkg/process/v4/transformers/github/test-fixtures/github-github-python-0.json b/pkg/process/v4/transformers/github/test-fixtures/github-github-python-0.json deleted file mode 100644 index ad14aa60..00000000 --- a/pkg/process/v4/transformers/github/test-fixtures/github-github-python-0.json +++ /dev/null @@ -1,58 +0,0 @@ -[ - { - "Advisory": { - "CVE": [ - "CVE-2018-8768" - ], - "FixedIn": [ - { - "ecosystem": "python", - "identifier": "5.4.1", - "name": "notebook", - "namespace": "github:python", - "range": "< 5.4.1" - } - ], - "Metadata": { - "CVE": [ - "CVE-2018-8768" - ] - }, - "Severity": "Low", - "Summary": "Low severity vulnerability that affects notebook", - "ghsaId": "GHSA-6cwv-x26c-w2q4", - "namespace": "github:python", - "url": "https://github.com/advisories/GHSA-6cwv-x26c-w2q4", - "withdrawn": null - }, - "Vulnerability": {} - }, - { - "Advisory": { - "CVE": [ - "CVE-2017-5524" - ], - "FixedIn": [ - { - "ecosystem": "python", - "identifier": "4.3.12", - "name": "Plone", - "namespace": "github:python", - "range": ">= 4.0 < 4.3.12" - } - ], - "Metadata": { - "CVE": [ - "CVE-2017-5524" - ] - }, - "Severity": "Medium", - "Summary": "Moderate severity vulnerability that affects Plone", - "ghsaId": "GHSA-p5wr-vp8g-q5p4", - "namespace": "github:python", - "url": "https://github.com/advisories/GHSA-p5wr-vp8g-q5p4", - "withdrawn": null - }, - "Vulnerability": {} - } -] \ No newline at end of file diff --git a/pkg/process/v4/transformers/github/test-fixtures/github-github-python-1.json b/pkg/process/v4/transformers/github/test-fixtures/github-github-python-1.json deleted file mode 100644 index bfa84922..00000000 --- a/pkg/process/v4/transformers/github/test-fixtures/github-github-python-1.json +++ /dev/null @@ -1,43 +0,0 @@ - -{ - "Advisory": { - "CVE": [ - "CVE-2017-5524" - ], - "FixedIn": [ - { - "ecosystem": "python", - "identifier": "4.3.12", - "name": "Plone", - "namespace": "github:python", - "range": ">= 4.0 < 4.3.12" - }, - { - "ecosystem": "python", - "identifier": "5.1b1", - "name": "Plone", - "namespace": "github:python", - "range": ">= 5.1a1 < 5.1b1" - }, - { - "ecosystem": "python", - "identifier": "5.0.7", - "name": "Plone", - "namespace": "github:python", - "range": ">= 5.0rc1 < 5.0.7" - } - ], - "Metadata": { - "CVE": [ - "CVE-2017-5524" - ] - }, - "Severity": "Medium", - "Summary": "Moderate severity vulnerability that affects Plone", - "ghsaId": "GHSA-p5wr-vp8g-q5p4", - "namespace": "github:python", - "url": "https://github.com/advisories/GHSA-p5wr-vp8g-q5p4", - "withdrawn": null - }, - "Vulnerability": {} -} diff --git a/pkg/process/v4/transformers/github/test-fixtures/github-withdrawn.json b/pkg/process/v4/transformers/github/test-fixtures/github-withdrawn.json deleted file mode 100644 index 04995e38..00000000 --- a/pkg/process/v4/transformers/github/test-fixtures/github-withdrawn.json +++ /dev/null @@ -1,29 +0,0 @@ - -{ - "Advisory": { - "CVE": [ - "CVE-2018-8768" - ], - "FixedIn": [ - { - "ecosystem": "python", - "identifier": "5.4.1", - "name": "notebook", - "namespace": "github:python", - "range": "< 5.4.1" - } - ], - "Metadata": { - "CVE": [ - "CVE-2018-8768" - ] - }, - "Severity": "Low", - "Summary": "Low severity vulnerability that affects notebook", - "ghsaId": "GHSA-6cwv-x26c-w2q4", - "namespace": "github:python", - "url": "https://github.com/advisories/GHSA-6cwv-x26c-w2q4", - "withdrawn": "2022-01-31T14:32:09Z" - }, - "Vulnerability": {} -} diff --git a/pkg/process/v4/transformers/github/test-fixtures/multiple-fixed-in-names.json b/pkg/process/v4/transformers/github/test-fixtures/multiple-fixed-in-names.json deleted file mode 100644 index ac1ef982..00000000 --- a/pkg/process/v4/transformers/github/test-fixtures/multiple-fixed-in-names.json +++ /dev/null @@ -1,43 +0,0 @@ - -{ - "Advisory": { - "CVE": [ - "CVE-2017-5524" - ], - "FixedIn": [ - { - "ecosystem": "python", - "identifier": "4.3.12", - "name": "Plone", - "namespace": "github:python", - "range": ">= 4.0 < 4.3.12" - }, - { - "ecosystem": "python", - "identifier": "5.1b1", - "name": "Plone", - "namespace": "github:python", - "range": ">= 5.1a1 < 5.1b1" - }, - { - "ecosystem": "python", - "identifier": "5.0.7", - "name": "Plone-debug", - "namespace": "github:python", - "range": ">= 5.0rc1 < 5.0.7" - } - ], - "Metadata": { - "CVE": [ - "CVE-2017-5524" - ] - }, - "Severity": "Medium", - "Summary": "Moderate severity vulnerability that affects Plone", - "ghsaId": "GHSA-p5wr-vp8g-q5p4", - "namespace": "github:python", - "url": "https://github.com/advisories/GHSA-p5wr-vp8g-q5p4", - "withdrawn": null - }, - "Vulnerability": {} -} diff --git a/pkg/process/v4/transformers/github/transform.go b/pkg/process/v4/transformers/github/transform.go deleted file mode 100644 index 7b88d608..00000000 --- a/pkg/process/v4/transformers/github/transform.go +++ /dev/null @@ -1,138 +0,0 @@ -package github - -import ( - "fmt" - "strings" - - "github.com/anchore/grype-db/pkg/data" - "github.com/anchore/grype-db/pkg/process/internal/common" - "github.com/anchore/grype-db/pkg/process/v4/transformers" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v4" - "github.com/anchore/grype/grype/db/v4/namespace" - syftPkg "github.com/anchore/syft/syft/pkg" -) - -const ( - // TODO: tech debt from a previous design - feed = "github" -) - -func buildGrypeNamespace(feed, group string) (namespace.Namespace, error) { - if feed != "github" { - return nil, fmt.Errorf("unable to determine grype namespace for enterprise feed=%s, group=%s", feed, group) - } - - feedGroupComponents := strings.Split(group, ":") - - if len(feedGroupComponents) < 2 { - return nil, fmt.Errorf("unable to determine grype namespace for enterprise feed=%s, group=%s", feed, group) - } - - feedGroupLang := feedGroupComponents[1] - syftLanguage := syftPkg.LanguageByName(feedGroupLang) - - if syftLanguage == syftPkg.UnknownLanguage { - // For now map nuget to dotnet as the language. - if feedGroupLang == "nuget" { - syftLanguage = syftPkg.Dotnet - } else { - return nil, fmt.Errorf("unable to determine grype namespace for enterprise feed=%s, group=%s", feed, group) - } - } - - ns, err := namespace.FromString(fmt.Sprintf("github:language:%s", string(syftLanguage))) - - if err != nil { - return nil, err - } - - return ns, nil -} - -func Transform(vulnerability unmarshal.GitHubAdvisory) ([]data.Entry, error) { - var allVulns []grypeDB.Vulnerability - - // Exclude entries marked as withdrawn - if vulnerability.Advisory.Withdrawn != "" { - return nil, nil - } - - recordSource := fmt.Sprintf("%s:%s", feed, vulnerability.Advisory.Namespace) - grypeNamespace, err := buildGrypeNamespace(feed, vulnerability.Advisory.Namespace) - if err != nil { - return nil, err - } - - entryNamespace := grypeNamespace.String() - - // there may be multiple packages indicated within the FixedIn field, we should make - // separate vulnerability entries (one for each name|namespaces combo) while merging - // constraint ranges as they are found. - for idx, fixedInEntry := range vulnerability.Advisory.FixedIn { - constraint := common.EnforceSemVerConstraint(fixedInEntry.Range) - - var versionFormat string - switch entryNamespace { - case "github:language:python": - versionFormat = "python" - default: - versionFormat = "unknown" - } - - // create vulnerability entry - allVulns = append(allVulns, grypeDB.Vulnerability{ - ID: vulnerability.Advisory.GhsaID, - VersionConstraint: constraint, - VersionFormat: versionFormat, - RelatedVulnerabilities: getRelatedVulnerabilities(vulnerability), - PackageName: grypeNamespace.Resolver().Normalize(fixedInEntry.Name), - Namespace: entryNamespace, - Fix: getFix(vulnerability, idx), - }) - } - - // create vulnerability metadata entry (a single entry keyed off of the vulnerability ID) - metadata := grypeDB.VulnerabilityMetadata{ - ID: vulnerability.Advisory.GhsaID, - DataSource: vulnerability.Advisory.URL, - Namespace: entryNamespace, - RecordSource: recordSource, - Severity: vulnerability.Advisory.Severity, - URLs: []string{vulnerability.Advisory.URL}, - Description: vulnerability.Advisory.Summary, - } - - return transformers.NewEntries(allVulns, metadata), nil -} - -func getFix(entry unmarshal.GitHubAdvisory, idx int) grypeDB.Fix { - fixedInEntry := entry.Advisory.FixedIn[idx] - - var fixedInVersions []string - fixedInVersion := common.CleanFixedInVersion(fixedInEntry.Identifier) - if fixedInVersion != "" { - fixedInVersions = append(fixedInVersions, fixedInVersion) - } - - fixState := grypeDB.NotFixedState - if len(fixedInVersions) > 0 { - fixState = grypeDB.FixedState - } - - return grypeDB.Fix{ - Versions: fixedInVersions, - State: fixState, - } -} - -func getRelatedVulnerabilities(entry unmarshal.GitHubAdvisory) []grypeDB.VulnerabilityReference { - vulns := make([]grypeDB.VulnerabilityReference, len(entry.Advisory.CVE)) - for idx, cve := range entry.Advisory.CVE { - vulns[idx] = grypeDB.VulnerabilityReference{ - ID: cve, - Namespace: "nvd:cpe", - } - } - return vulns -} diff --git a/pkg/process/v4/transformers/github/transform_test.go b/pkg/process/v4/transformers/github/transform_test.go deleted file mode 100644 index 85343c43..00000000 --- a/pkg/process/v4/transformers/github/transform_test.go +++ /dev/null @@ -1,255 +0,0 @@ -package github - -import ( - "os" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - testUtils "github.com/anchore/grype-db/pkg/process/internal/tests" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v4" - "github.com/anchore/grype/grype/db/v4/namespace" - "github.com/anchore/grype/grype/db/v4/namespace/language" - syftPkg "github.com/anchore/syft/syft/pkg" -) - -func TestBuildGrypeNamespace(t *testing.T) { - tests := []struct { - feed string - group string - namespace namespace.Namespace - }{ - { - feed: "github", - group: "github:python", - namespace: language.NewNamespace("github", syftPkg.Python, ""), - }, - { - feed: "github", - group: "github:composer", - namespace: language.NewNamespace("github", syftPkg.PHP, ""), - }, - { - feed: "github", - group: "github:gem", - namespace: language.NewNamespace("github", syftPkg.Ruby, ""), - }, - { - feed: "github", - group: "github:npm", - namespace: language.NewNamespace("github", syftPkg.JavaScript, ""), - }, - { - feed: "github", - group: "github:go", - namespace: language.NewNamespace("github", syftPkg.Go, ""), - }, - { - feed: "github", - group: "github:nuget", - namespace: language.NewNamespace("github", syftPkg.Dotnet, ""), - }, - { - feed: "github", - group: "github:rust", - namespace: language.NewNamespace("github", syftPkg.Rust, ""), - }, - } - - for _, test := range tests { - ns, err := buildGrypeNamespace(test.feed, test.group) - - assert.NoError(t, err) - assert.Equal(t, test.namespace, ns) - } -} - -func TestUnmarshalGitHubEntries(t *testing.T) { - f, err := os.Open("test-fixtures/github-github-python-0.json") - require.NoError(t, err) - defer testUtils.CloseFile(f) - - entries, err := unmarshal.GitHubAdvisoryEntries(f) - require.NoError(t, err) - - assert.Len(t, entries, 2) - -} - -func TestParseGitHubEntry(t *testing.T) { - expectedVulns := []grypeDB.Vulnerability{ - { - ID: "GHSA-p5wr-vp8g-q5p4", - VersionConstraint: ">=4.0,<4.3.12", - VersionFormat: "python", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2017-5524", - Namespace: "nvd:cpe", - }, - }, - PackageName: "plone", - Namespace: "github:language:python", - Fix: grypeDB.Fix{ - Versions: []string{"4.3.12"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "GHSA-p5wr-vp8g-q5p4", - VersionConstraint: ">=5.1a1,<5.1b1", - VersionFormat: "python", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2017-5524", - Namespace: "nvd:cpe", - }, - }, - PackageName: "plone", - Namespace: "github:language:python", - Fix: grypeDB.Fix{ - Versions: []string{"5.1b1"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "GHSA-p5wr-vp8g-q5p4", - VersionConstraint: ">=5.0rc1,<5.0.7", - VersionFormat: "python", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2017-5524", - Namespace: "nvd:cpe", - }, - }, - PackageName: "plone", - Namespace: "github:language:python", - Fix: grypeDB.Fix{ - Versions: []string{"5.0.7"}, - State: grypeDB.FixedState, - }, - }, - } - - expectedMetadata := grypeDB.VulnerabilityMetadata{ - ID: "GHSA-p5wr-vp8g-q5p4", - Namespace: "github:language:python", - RecordSource: "github:github:python", - DataSource: "https://github.com/advisories/GHSA-p5wr-vp8g-q5p4", - Severity: "Medium", - URLs: []string{"https://github.com/advisories/GHSA-p5wr-vp8g-q5p4"}, - Description: "Moderate severity vulnerability that affects Plone", - } - - f, err := os.Open("test-fixtures/github-github-python-1.json") - require.NoError(t, err) - defer testUtils.CloseFile(f) - - entries, err := unmarshal.GitHubAdvisoryEntries(f) - require.NoError(t, err) - - require.Len(t, entries, 1) - - entry := entries[0] - - dataEntries, err := Transform(entry) - require.NoError(t, err) - - var vulns []grypeDB.Vulnerability - for _, entry := range dataEntries { - switch vuln := entry.Data.(type) { - case grypeDB.Vulnerability: - vulns = append(vulns, vuln) - case grypeDB.VulnerabilityMetadata: - assert.Equal(t, expectedMetadata, vuln) - default: - t.Fatalf("unexpected condition: data entry does not have a vulnerability or a metadata") - } - } - - // check vulnerability - assert.Len(t, vulns, len(expectedVulns)) - - if diff := cmp.Diff(expectedVulns, vulns); diff != "" { - t.Errorf("vulnerabilities do not match (-want +got):\n%s", diff) - } - -} - -func TestDefaultVersionFormatNpmGitHubEntry(t *testing.T) { - expectedVuln := grypeDB.Vulnerability{ - ID: "GHSA-vc9j-fhvv-8vrf", - VersionConstraint: "<=0.2.0-prerelease.20200709173451", - VersionFormat: "unknown", // TODO: this should reference a format, yes? (not a string) - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2020-14000", - Namespace: "nvd:cpe", - }, - }, - PackageName: "scratch-vm", - Namespace: "github:language:javascript", - Fix: grypeDB.Fix{ - Versions: []string{"0.2.0-prerelease.20200714185213"}, - State: grypeDB.FixedState, - }, - } - - expectedMetadata := grypeDB.VulnerabilityMetadata{ - ID: "GHSA-vc9j-fhvv-8vrf", - Namespace: "github:language:javascript", - RecordSource: "github:github:npm", - DataSource: "https://github.com/advisories/GHSA-vc9j-fhvv-8vrf", - Severity: "High", - URLs: []string{"https://github.com/advisories/GHSA-vc9j-fhvv-8vrf"}, - Description: "Remote Code Execution in scratch-vm", - } - - f, err := os.Open("test-fixtures/github-github-npm-0.json") - require.NoError(t, err) - defer testUtils.CloseFile(f) - - entries, err := unmarshal.GitHubAdvisoryEntries(f) - require.NoError(t, err) - - require.Len(t, entries, 1) - - entry := entries[0] - - dataEntries, err := Transform(entry) - assert.NoError(t, err) - - for _, entry := range dataEntries { - switch vuln := entry.Data.(type) { - case grypeDB.Vulnerability: - assert.Equal(t, expectedVuln, vuln) - case grypeDB.VulnerabilityMetadata: - assert.Equal(t, expectedMetadata, vuln) - default: - t.Fatalf("unexpected condition: data entry does not have a vulnerability or a metadata") - } - } - - // check vulnerability - assert.Len(t, dataEntries, 2) -} - -func TestFilterWithdrawnEntries(t *testing.T) { - f, err := os.Open("test-fixtures/github-withdrawn.json") - require.NoError(t, err) - defer testUtils.CloseFile(f) - - entries, err := unmarshal.GitHubAdvisoryEntries(f) - require.NoError(t, err) - - require.Len(t, entries, 1) - - entry := entries[0] - - dataEntries, err := Transform(entry) - assert.NoError(t, err) - assert.Nil(t, dataEntries) -} diff --git a/pkg/process/v4/transformers/matchexclusions/transform.go b/pkg/process/v4/transformers/matchexclusions/transform.go deleted file mode 100644 index c4831be1..00000000 --- a/pkg/process/v4/transformers/matchexclusions/transform.go +++ /dev/null @@ -1,42 +0,0 @@ -package matchexclusions - -import ( - "github.com/anchore/grype-db/pkg/data" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v4" -) - -func Transform(matchExclusion unmarshal.MatchExclusion) ([]data.Entry, error) { - exclusion := grypeDB.VulnerabilityMatchExclusion{ - ID: matchExclusion.ID, - Constraints: nil, - Justification: matchExclusion.Justification, - } - - for _, c := range matchExclusion.Constraints { - constraint := &grypeDB.VulnerabilityMatchExclusionConstraint{ - Vulnerability: grypeDB.VulnerabilityExclusionConstraint{ - Namespace: c.Vulnerability.Namespace, - FixState: grypeDB.FixState(c.Vulnerability.FixState), - }, - Package: grypeDB.PackageExclusionConstraint{ - Name: c.Package.Name, - Language: c.Package.Language, - Type: c.Package.Type, - Version: c.Package.Version, - Location: c.Package.Location, - }, - } - - exclusion.Constraints = append(exclusion.Constraints, *constraint) - } - - entries := []data.Entry{ - { - DBSchemaVersion: grypeDB.SchemaVersion, - Data: exclusion, - }, - } - - return entries, nil -} diff --git a/pkg/process/v4/transformers/msrc/test-fixtures/microsoft-msrc-0.json b/pkg/process/v4/transformers/msrc/test-fixtures/microsoft-msrc-0.json deleted file mode 100644 index 474b23b2..00000000 --- a/pkg/process/v4/transformers/msrc/test-fixtures/microsoft-msrc-0.json +++ /dev/null @@ -1,194 +0,0 @@ -[ - { - "cvss": { - "base_score": 7.8, - "temporal_score": 7, - "vector": "CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H/E:P/RL:O/RC:C" - }, - "fixed_in": [ - { - "id": "4493470", - "is_first": true, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4493470", - "https://support.microsoft.com/help/4493470" - ] - }, - { - "id": "4494440", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4494440", - "https://support.microsoft.com/help/4494440" - ] - }, - { - "id": "4503267", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4503267", - "https://support.microsoft.com/en-us/help/4503267" - ] - }, - { - "id": "4507460", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4507460", - "https://support.microsoft.com/help/4507460" - ] - }, - { - "id": "4512517", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4512517", - "https://support.microsoft.com/help/4512517" - ] - }, - { - "id": "4516044", - "is_first": false, - "is_latest": true, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4516044", - "https://support.microsoft.com/help/4516044" - ] - } - ], - "id": "CVE-2019-0671", - "link": "https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-0671", - "product": { - "family": "Windows", - "id": "10852", - "name": "Windows 10 Version 1607 for 32-bit Systems" - }, - "severity": "High", - "summary": "Microsoft Office Access Connectivity Engine Remote Code Execution Vulnerability", - "vulnerable": [ - "4480961", - "4483229", - "4487026", - "4489882" - ] - }, -{ - "cvss": { - "base_score": 4.4, - "temporal_score": 4, - "vector": "CVSS:3.0/AV:L/AC:H/PR:L/UI:R/S:U/C:N/I:N/A:H/E:P/RL:O/RC:C" - }, - "fixed_in": [ - { - "id": "4093119", - "is_first": true, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4093119" - ] - }, - { - "id": "4103723", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4103723" - ] - }, - { - "id": "4284880", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4284880" - ] - }, - { - "id": "4338814", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4338814" - ] - }, - { - "id": "4343887", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4343887" - ] - }, - { - "id": "4345418", - "is_first": false, - "is_latest": true, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4345418" - ] - }, - { - "id": "4457131", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4457131" - ] - }, - { - "id": "4462917", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4462917" - ] - }, - { - "id": "4467691", - "is_first": false, - "is_latest": false, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4467691" - ] - }, - { - "id": "4471321", - "is_first": false, - "is_latest": true, - "links": [ - "https://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB4471321" - ] - } - ], - "id": "CVE-2018-8116", - "link": "https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-8116", - "product": { - "family": "Windows", - "id": "10852", - "name": "Windows 10 Version 1607 for 32-bit Systems" - }, - "severity": "Medium", - "summary": "Microsoft Graphics Component Denial of Service Vulnerability", - "vulnerable": [ - "3213986", - "4013429", - "4015217", - "4019472", - "4022715", - "4025339", - "4034658", - "4038782", - "4041691", - "4048953", - "4053579", - "4056890", - "4074590", - "4088787" - ] - } -] diff --git a/pkg/process/v4/transformers/msrc/transform.go b/pkg/process/v4/transformers/msrc/transform.go deleted file mode 100644 index 6ccc225c..00000000 --- a/pkg/process/v4/transformers/msrc/transform.go +++ /dev/null @@ -1,114 +0,0 @@ -package msrc - -import ( - "fmt" - "strings" - - "github.com/anchore/grype-db/pkg/data" - "github.com/anchore/grype-db/pkg/process/internal/common" - "github.com/anchore/grype-db/pkg/process/v4/transformers" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v4" - "github.com/anchore/grype/grype/db/v4/namespace" - "github.com/anchore/grype/grype/distro" -) - -const ( - // TODO: tech debt from a previous design - feed = "microsoft" - groupPrefix = "msrc" -) - -func buildGrypeNamespace(feed, group string) (namespace.Namespace, error) { - if feed != "microsoft" || !strings.HasPrefix(group, "msrc:") { - return nil, fmt.Errorf("invalid source for feed=%s, group=%s", feed, group) - } - components := strings.Split(group, ":") - - if len(components) != 2 { - return nil, fmt.Errorf("invalid source for feed=%s, group=%s", feed, group) - } - ns, err := namespace.FromString(fmt.Sprintf("msrc:distro:%s:%s", distro.Windows, components[1])) - - if err != nil { - return nil, err - } - - return ns, nil -} - -// Transform gets called by the parser, which consumes entries from the JSON files previously pulled. Each VulnDBVulnerability represents -// a single unmarshalled entry from the feed service -func Transform(vulnerability unmarshal.MSRCVulnerability) ([]data.Entry, error) { - group := fmt.Sprintf("%s:%s", groupPrefix, vulnerability.Product.ID) - recordSource := fmt.Sprintf("%s:%s", feed, group) - grypeNamespace, err := buildGrypeNamespace(feed, group) - if err != nil { - return nil, err - } - - entryNamespace := grypeNamespace.String() - - // In anchore-enterprise windows analyzer, "base" represents unpatched windows images (images with no KBs). - // If a vulnerability exists for a Microsoft Product ID and the image has no KBs (which are patches), - // then the image must be vulnerable to the image. - //nolint:gocritic - versionConstraint := append(vulnerability.Vulnerable, "base") - - allVulns := []grypeDB.Vulnerability{ - { - ID: vulnerability.ID, - VersionConstraint: common.OrConstraints(versionConstraint...), - VersionFormat: "kb", - PackageName: grypeNamespace.Resolver().Normalize(vulnerability.Product.ID), - Namespace: entryNamespace, - Fix: getFix(vulnerability), - }, - } - - // create vulnerability metadata entry (a single entry keyed off of the vulnerability ID) - metadata := grypeDB.VulnerabilityMetadata{ - ID: vulnerability.ID, - DataSource: vulnerability.Link, - Namespace: entryNamespace, - RecordSource: recordSource, - Severity: vulnerability.Severity, - URLs: []string{vulnerability.Link}, - // There is no description for vulnerabilities from the feed service - // summary gives something like "windows information disclosure vulnerability" - //Description: vulnerability.Summary, - Cvss: []grypeDB.Cvss{ - { - Metrics: grypeDB.CvssMetrics{BaseScore: vulnerability.Cvss.BaseScore}, - Vector: vulnerability.Cvss.Vector, - }, - }, - } - - return transformers.NewEntries(allVulns, metadata), nil -} - -func getFix(entry unmarshal.MSRCVulnerability) grypeDB.Fix { - fixedInVersion := fixedInKB(entry) - fixState := grypeDB.FixedState - - if fixedInVersion == "" { - fixState = grypeDB.NotFixedState - } - - return grypeDB.Fix{ - Versions: []string{fixedInVersion}, - State: fixState, - } -} - -// fixedInKB finds the "latest" patch (KB id) amongst the available microsoft patches and returns it -// if the "latest" patch cannot be found, an error is returned -func fixedInKB(vulnerability unmarshal.MSRCVulnerability) string { - for _, fixedIn := range vulnerability.FixedIn { - if fixedIn.IsLatest { - return fixedIn.ID - } - } - return "" -} diff --git a/pkg/process/v4/transformers/msrc/transform_test.go b/pkg/process/v4/transformers/msrc/transform_test.go deleted file mode 100644 index 565df2bb..00000000 --- a/pkg/process/v4/transformers/msrc/transform_test.go +++ /dev/null @@ -1,120 +0,0 @@ -package msrc - -import ( - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - testUtils "github.com/anchore/grype-db/pkg/process/internal/tests" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v4" -) - -func TestUnmarshalMsrcVulnerabilities(t *testing.T) { - f, err := os.Open("test-fixtures/microsoft-msrc-0.json") - require.NoError(t, err) - defer testUtils.CloseFile(f) - - entries, err := unmarshal.MSRCVulnerabilityEntries(f) - require.NoError(t, err) - - assert.Equal(t, len(entries), 2) -} - -func TestParseMSRCEntry(t *testing.T) { - expectedVulns := []struct { - vulnerability grypeDB.Vulnerability - metadata grypeDB.VulnerabilityMetadata - }{ - { - vulnerability: grypeDB.Vulnerability{ - ID: "CVE-2019-0671", - VersionConstraint: `4480961 || 4483229 || 4487026 || 4489882 || base`, - VersionFormat: "kb", - PackageName: "10852", - Namespace: "msrc:distro:windows:10852", - Fix: grypeDB.Fix{ - Versions: []string{"4516044"}, - State: grypeDB.FixedState, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2019-0671", - Severity: "High", - DataSource: "https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-0671", - URLs: []string{"https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-0671"}, - Description: "", - RecordSource: "microsoft:msrc:10852", - Namespace: "msrc:distro:windows:10852", - Cvss: []grypeDB.Cvss{ - { - Metrics: grypeDB.CvssMetrics{ - BaseScore: 7.8, - ImpactScore: nil, - }, - Vector: "CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H/E:P/RL:O/RC:C", - }, - }, - }, - }, - { - vulnerability: grypeDB.Vulnerability{ - ID: "CVE-2018-8116", - VersionConstraint: `3213986 || 4013429 || 4015217 || 4019472 || 4022715 || 4025339 || 4034658 || 4038782 || 4041691 || 4048953 || 4053579 || 4056890 || 4074590 || 4088787 || base`, - VersionFormat: "kb", - PackageName: "10852", - Namespace: "msrc:distro:windows:10852", - Fix: grypeDB.Fix{ - Versions: []string{"4345418"}, - State: grypeDB.FixedState, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2018-8116", - Namespace: "msrc:distro:windows:10852", - DataSource: "https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-8116", - RecordSource: "microsoft:msrc:10852", - Severity: "Medium", - URLs: []string{"https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-8116"}, - Description: "", - Cvss: []grypeDB.Cvss{ - { - Metrics: grypeDB.CvssMetrics{ - BaseScore: 4.4, - ImpactScore: nil, - }, - Vector: "CVSS:3.0/AV:L/AC:H/PR:L/UI:R/S:U/C:N/I:N/A:H/E:P/RL:O/RC:C", - }, - }, - }, - }, - } - - f, err := os.Open("test-fixtures/microsoft-msrc-0.json") - require.NoError(t, err) - defer testUtils.CloseFile(f) - - entries, err := unmarshal.MSRCVulnerabilityEntries(f) - require.NoError(t, err) - - require.Equal(t, len(entries), 2) - - for idx, entry := range entries { - dataEntries, err := Transform(entry) - require.NoError(t, err) - assert.Len(t, dataEntries, 2) - expected := expectedVulns[idx] - for _, entry := range dataEntries { - switch vuln := entry.Data.(type) { - case grypeDB.Vulnerability: - assert.Equal(t, expected.vulnerability, vuln) - case grypeDB.VulnerabilityMetadata: - assert.Equal(t, expected.metadata, vuln) - default: - t.Fatalf("unexpected condition: data entry does not have a vulnerability or a metadata") - } - } - } -} diff --git a/pkg/process/v4/transformers/nvd/test-fixtures/compound-pkg.json b/pkg/process/v4/transformers/nvd/test-fixtures/compound-pkg.json deleted file mode 100644 index 8e658dcd..00000000 --- a/pkg/process/v4/transformers/nvd/test-fixtures/compound-pkg.json +++ /dev/null @@ -1,115 +0,0 @@ -{ - "cve": { - "id": "CVE-2018-10189", - "sourceIdentifier": "cve@mitre.org", - "published": "2018-04-17T20:29:00.410", - "lastModified": "2018-05-23T14:41:49.073", - "vulnStatus": "Analyzed", - "descriptions": [ - { - "lang": "en", - "value": "An issue was discovered in Mautic 1.x and 2.x before 2.13.0. It is possible to systematically emulate tracking cookies per contact due to tracking the contact by their auto-incremented ID. Thus, a third party can manipulate the cookie value with +1 to systematically assume being tracked as each contact in Mautic. It is then possible to retrieve information about the contact through forms that have progressive profiling enabled." - }, - { - "lang": "es", - "value": "Se ha descubierto un problema en Mautic, en versiones 1.x y 2.x anteriores a la 2.13.0. Es posible emular de forma sistemática el rastreo de cookies por contacto debido al rastreo de contacto por su ID autoincrementada. Por lo tanto, un tercero puede manipular el valor de la cookie con un +1 para asumir sistemáticamente que se está rastreando como cada contacto en Mautic. Así, sería posible recuperar información sobre el contacto a través de formularios que tengan habilitada la generación de perfiles progresiva." - } - ], - "metrics": { - "cvssMetricV30": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "3.0", - "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", - "attackVector": "NETWORK", - "attackComplexity": "LOW", - "privilegesRequired": "NONE", - "userInteraction": "NONE", - "scope": "UNCHANGED", - "confidentialityImpact": "HIGH", - "integrityImpact": "NONE", - "availabilityImpact": "NONE", - "baseScore": 7.5, - "baseSeverity": "HIGH" - }, - "exploitabilityScore": 3.9, - "impactScore": 3.6 - } - ], - "cvssMetricV2": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "2.0", - "vectorString": "AV:N/AC:L/Au:N/C:P/I:N/A:N", - "accessVector": "NETWORK", - "accessComplexity": "LOW", - "authentication": "NONE", - "confidentialityImpact": "PARTIAL", - "integrityImpact": "NONE", - "availabilityImpact": "NONE", - "baseScore": 5.0 - }, - "baseSeverity": "MEDIUM", - "exploitabilityScore": 10.0, - "impactScore": 2.9, - "acInsufInfo": false, - "obtainAllPrivilege": false, - "obtainUserPrivilege": false, - "obtainOtherPrivilege": false, - "userInteractionRequired": false - } - ] - }, - "weaknesses": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "description": [ - { - "lang": "en", - "value": "CWE-200" - } - ] - } - ], - "configurations": [ - { - "nodes": [ - { - "operator": "OR", - "negate": false, - "cpeMatch": [ - { - "vulnerable": true, - "criteria": "cpe:2.3:a:mautic:mautic:*:*:*:*:*:*:*:*", - "versionStartIncluding": "1.0.0", - "versionEndIncluding": "1.4.1", - "matchCriteriaId": "5779710D-099E-40EE-8DF3-55BD3179A50C" - }, - { - "vulnerable": true, - "criteria": "cpe:2.3:a:mautic:mautic:*:*:*:*:*:*:*:*", - "versionStartIncluding": "2.0.0", - "versionEndExcluding": "2.13.0", - "matchCriteriaId": "4EFAEE48-4AEF-4F8C-95E0-6E8D848D900F" - } - ] - } - ] - } - ], - "references": [ - { - "url": "https://github.com/mautic/mautic/releases/tag/2.13.0", - "source": "cve@mitre.org", - "tags": [ - "Third Party Advisory" - ] - } - ] - } -} diff --git a/pkg/process/v4/transformers/nvd/test-fixtures/invalid_cpe.json b/pkg/process/v4/transformers/nvd/test-fixtures/invalid_cpe.json deleted file mode 100644 index eac2ebd4..00000000 --- a/pkg/process/v4/transformers/nvd/test-fixtures/invalid_cpe.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "cve": { - "id": "CVE-2015-8978", - "sourceIdentifier": "cve@mitre.org", - "published": "2016-11-22T17:59:00.180", - "lastModified": "2016-11-28T19:50:59.600", - "vulnStatus": "Modified", - "descriptions": [ - { - "lang": "en", - "value": "In Soap Lite (aka the SOAP::Lite extension for Perl) 1.14 and earlier, an example attack consists of defining 10 or more XML entities, each defined as consisting of 10 of the previous entity, with the document consisting of a single instance of the largest entity, which expands to one billion copies of the first entity. The amount of computer memory used for handling an external SOAP call would likely exceed that available to the process parsing the XML." - }, - { - "lang": "es", - "value": "En Soap Lite (también conocido como la extensión SOAP::Lite para Perl) 1.14 y versiones anteriores, un ejemplo de ataque consiste en definir 10 o más entidades XML, cada una definida como consistente de 10 de la entidad anterior, con el documento consistente de una única instancia de la entidad más grande, que se expande a mil millones de copias de la primera entidad. La suma de la memoria del ordenador utilizada para manejar una llamada SOAP externa probablemente superaría el disponible para el proceso de análisis del XML." - } - ], - "metrics": { - "cvssMetricV30": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "3.0", - "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - "attackVector": "NETWORK", - "attackComplexity": "LOW", - "privilegesRequired": "NONE", - "userInteraction": "NONE", - "scope": "UNCHANGED", - "confidentialityImpact": "NONE", - "integrityImpact": "NONE", - "availabilityImpact": "HIGH", - "baseScore": 7.5, - "baseSeverity": "HIGH" - }, - "exploitabilityScore": 3.9, - "impactScore": 3.6 - } - ], - "cvssMetricV2": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "2.0", - "vectorString": "AV:N/AC:L/Au:N/C:N/I:N/A:P", - "accessVector": "NETWORK", - "accessComplexity": "LOW", - "authentication": "NONE", - "confidentialityImpact": "NONE", - "integrityImpact": "NONE", - "availabilityImpact": "PARTIAL", - "baseScore": 5.0 - }, - "baseSeverity": "MEDIUM", - "exploitabilityScore": 10.0, - "impactScore": 2.9, - "acInsufInfo": false, - "obtainAllPrivilege": false, - "obtainUserPrivilege": false, - "obtainOtherPrivilege": false, - "userInteractionRequired": false - } - ] - }, - "weaknesses": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "description": [ - { - "lang": "en", - "value": "CWE-399" - } - ] - } - ], - "configurations": [ - { - "nodes": [ - { - "operator": "OR", - "negate": false, - "cpeMatch": [ - { - "vulnerable": true, - "criteria": "cpe:2.3:a:soap::lite_project:soap::lite:*:*:*:*:*:perl:*:*", - "versionEndIncluding": "1.14", - "matchCriteriaId": "FB4DACB9-2E9E-4CBE-825F-FC0303D8CC86" - } - ] - } - ] - } - ], - "references": [ - { - "url": "http://cpansearch.perl.org/src/PHRED/SOAP-Lite-1.20/Changes", - "source": "cve@mitre.org", - "tags": [ - "Vendor Advisory" - ] - }, - { - "url": "http://www.securityfocus.com/bid/94487", - "source": "cve@mitre.org" - } - ] - } -} diff --git a/pkg/process/v4/transformers/nvd/test-fixtures/single-package-multi-distro.json b/pkg/process/v4/transformers/nvd/test-fixtures/single-package-multi-distro.json deleted file mode 100644 index ed108475..00000000 --- a/pkg/process/v4/transformers/nvd/test-fixtures/single-package-multi-distro.json +++ /dev/null @@ -1,174 +0,0 @@ -{ - "cve": { - "id": "CVE-2018-1000222", - "sourceIdentifier": "cve@mitre.org", - "published": "2018-08-20T20:29:01.347", - "lastModified": "2020-03-31T02:15:12.667", - "vulnStatus": "Modified", - "descriptions": [ - { - "lang": "en", - "value": "Libgd version 2.2.5 contains a Double Free Vulnerability vulnerability in gdImageBmpPtr Function that can result in Remote Code Execution . This attack appear to be exploitable via Specially Crafted Jpeg Image can trigger double free. This vulnerability appears to have been fixed in after commit ac16bdf2d41724b5a65255d4c28fb0ec46bc42f5." - }, - { - "lang": "es", - "value": "Libgd 2.2.5 contiene una vulnerabilidad de doble liberación (double free) en la función gdImageBmpPtr que puede resultar en la ejecución remota de código. Este ataque parece ser explotable mediante una imagen JPEG especialmente manipulada que desencadene una doble liberación (double free). La vulnerabilidad parece haber sido solucionada tras el commit con ID ac16bdf2d41724b5a65255d4c28fb0ec46bc42f5." - } - ], - "metrics": { - "cvssMetricV30": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "3.0", - "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - "attackVector": "NETWORK", - "attackComplexity": "LOW", - "privilegesRequired": "NONE", - "userInteraction": "REQUIRED", - "scope": "UNCHANGED", - "confidentialityImpact": "HIGH", - "integrityImpact": "HIGH", - "availabilityImpact": "HIGH", - "baseScore": 8.8, - "baseSeverity": "HIGH" - }, - "exploitabilityScore": 2.8, - "impactScore": 5.9 - } - ], - "cvssMetricV2": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "2.0", - "vectorString": "AV:N/AC:M/Au:N/C:P/I:P/A:P", - "accessVector": "NETWORK", - "accessComplexity": "MEDIUM", - "authentication": "NONE", - "confidentialityImpact": "PARTIAL", - "integrityImpact": "PARTIAL", - "availabilityImpact": "PARTIAL", - "baseScore": 6.8 - }, - "baseSeverity": "MEDIUM", - "exploitabilityScore": 8.6, - "impactScore": 6.4, - "acInsufInfo": false, - "obtainAllPrivilege": false, - "obtainUserPrivilege": false, - "obtainOtherPrivilege": false, - "userInteractionRequired": true - } - ] - }, - "weaknesses": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "description": [ - { - "lang": "en", - "value": "CWE-415" - } - ] - } - ], - "configurations": [ - { - "nodes": [ - { - "operator": "OR", - "negate": false, - "cpeMatch": [ - { - "vulnerable": true, - "criteria": "cpe:2.3:a:libgd:libgd:2.2.5:*:*:*:*:*:*:*", - "matchCriteriaId": "C257CC1C-BF6A-4125-AA61-9C2D09096084" - } - ] - } - ] - }, - { - "nodes": [ - { - "operator": "OR", - "negate": false, - "cpeMatch": [ - { - "vulnerable": true, - "criteria": "cpe:2.3:o:canonical:ubuntu_linux:14.04:*:*:*:lts:*:*:*", - "matchCriteriaId": "B5A6F2F3-4894-4392-8296-3B8DD2679084" - }, - { - "vulnerable": true, - "criteria": "cpe:2.3:o:canonical:ubuntu_linux:16.04:*:*:*:lts:*:*:*", - "matchCriteriaId": "F7016A2A-8365-4F1A-89A2-7A19F2BCAE5B" - }, - { - "vulnerable": true, - "criteria": "cpe:2.3:o:canonical:ubuntu_linux:18.04:*:*:*:lts:*:*:*", - "matchCriteriaId": "23A7C53F-B80F-4E6A-AFA9-58EEA84BE11D" - } - ] - } - ] - }, - { - "nodes": [ - { - "operator": "OR", - "negate": false, - "cpeMatch": [ - { - "vulnerable": true, - "criteria": "cpe:2.3:o:debian:debian_linux:8.0:*:*:*:*:*:*:*", - "matchCriteriaId": "C11E6FB0-C8C0-4527-9AA0-CB9B316F8F43" - } - ] - } - ] - } - ], - "references": [ - { - "url": "https://github.com/libgd/libgd/issues/447", - "source": "cve@mitre.org", - "tags": [ - "Issue Tracking", - "Third Party Advisory" - ] - }, - { - "url": "https://lists.debian.org/debian-lts-announce/2019/01/msg00028.html", - "source": "cve@mitre.org", - "tags": [ - "Mailing List", - "Third Party Advisory" - ] - }, - { - "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/3CZ2QADQTKRHTGB2AHD7J4QQNDLBEMM6/", - "source": "cve@mitre.org" - }, - { - "url": "https://security.gentoo.org/glsa/201903-18", - "source": "cve@mitre.org", - "tags": [ - "Third Party Advisory" - ] - }, - { - "url": "https://usn.ubuntu.com/3755-1/", - "source": "cve@mitre.org", - "tags": [ - "Mitigation", - "Third Party Advisory" - ] - } - ] - } -} diff --git a/pkg/process/v4/transformers/nvd/test-fixtures/unmarshal-test.json b/pkg/process/v4/transformers/nvd/test-fixtures/unmarshal-test.json deleted file mode 100644 index 2dc698fa..00000000 --- a/pkg/process/v4/transformers/nvd/test-fixtures/unmarshal-test.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "cve": { - "id": "CVE-2003-0349", - "sourceIdentifier": "cve@mitre.org", - "published": "2003-07-24T04:00:00.000", - "lastModified": "2018-10-12T21:32:41.083", - "vulnStatus": "Modified", - "descriptions": [ - { - "lang": "en", - "value": "Buffer overflow in the streaming media component for logging multicast requests in the ISAPI for the logging capability of Microsoft Windows Media Services (nsiislog.dll), as installed in IIS 5.0, allows remote attackers to execute arbitrary code via a large POST request to nsiislog.dll." - }, - { - "lang": "es", - "value": "Desbordamiento de búfer en el componente de secuenciamiento (streaming) de medios para registrar peticiones de multidifusión en la librería ISAPI de la capacidad de registro (logging) de Microsoft Windows Media Services (nsiislog.dll), como el instalado en IIS 5.9, permite a atacantes remotos ejecutar código arbitrario mediante una petición POST larga a nsiislog.dll." - } - ], - "metrics": { - "cvssMetricV2": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "2.0", - "vectorString": "AV:N/AC:L/Au:N/C:P/I:P/A:P", - "accessVector": "NETWORK", - "accessComplexity": "LOW", - "authentication": "NONE", - "confidentialityImpact": "PARTIAL", - "integrityImpact": "PARTIAL", - "availabilityImpact": "PARTIAL", - "baseScore": 7.5 - }, - "baseSeverity": "HIGH", - "exploitabilityScore": 10.0, - "impactScore": 6.4, - "acInsufInfo": false, - "obtainAllPrivilege": false, - "obtainUserPrivilege": true, - "obtainOtherPrivilege": false, - "userInteractionRequired": false - } - ] - }, - "weaknesses": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "description": [ - { - "lang": "en", - "value": "NVD-CWE-Other" - } - ] - } - ], - "configurations": [ - { - "nodes": [ - { - "operator": "OR", - "negate": false, - "cpeMatch": [ - { - "vulnerable": true, - "criteria": "cpe:2.3:o:microsoft:windows_2000:*:*:*:*:*:*:*:*", - "matchCriteriaId": "4E545C63-FE9C-4CA1-AF0F-D999D84D2AFD" - } - ] - } - ] - } - ], - "references": [ - { - "url": "http://marc.info/?l=bugtraq&m=105665030925504&w=2", - "source": "cve@mitre.org" - }, - { - "url": "http://securitytracker.com/id?1007059", - "source": "cve@mitre.org" - }, - { - "url": "http://www.kb.cert.org/vuls/id/113716", - "source": "cve@mitre.org", - "tags": [ - "US Government Resource" - ] - }, - { - "url": "http://www.ntbugtraq.com/default.asp?pid=36&sid=1&A2=ind0306&L=NTBUGTRAQ&P=R4563", - "source": "cve@mitre.org", - "tags": [ - "Exploit", - "Patch", - "Vendor Advisory" - ] - }, - { - "url": "https://docs.microsoft.com/en-us/security-updates/securitybulletins/2003/ms03-022", - "source": "cve@mitre.org" - }, - { - "url": "https://oval.cisecurity.org/repository/search/definition/oval%3Aorg.mitre.oval%3Adef%3A938", - "source": "cve@mitre.org" - } - ] - } -} diff --git a/pkg/process/v4/transformers/nvd/test-fixtures/version-range.json b/pkg/process/v4/transformers/nvd/test-fixtures/version-range.json deleted file mode 100644 index 3df5b86d..00000000 --- a/pkg/process/v4/transformers/nvd/test-fixtures/version-range.json +++ /dev/null @@ -1,121 +0,0 @@ -{ - "cve": { - "id": "CVE-2018-5487", - "sourceIdentifier": "security-alert@netapp.com", - "published": "2018-05-24T14:29:00.390", - "lastModified": "2018-07-05T13:52:30.627", - "vulnStatus": "Analyzed", - "descriptions": [ - { - "lang": "en", - "value": "NetApp OnCommand Unified Manager for Linux versions 7.2 through 7.3 ship with the Java Management Extension Remote Method Invocation (JMX RMI) service bound to the network, and are susceptible to unauthenticated remote code execution." - }, - { - "lang": "es", - "value": "NetApp OnCommand Unified Manager for Linux, de la versión 7.2 hasta la 7.3, se distribuye con el servicio Java Management Extension Remote Method Invocation (JMX RMI) enlazado a la red y es susceptible a la ejecución remota de código sin autenticación." - } - ], - "metrics": { - "cvssMetricV30": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "3.0", - "vectorString": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", - "attackVector": "NETWORK", - "attackComplexity": "LOW", - "privilegesRequired": "NONE", - "userInteraction": "NONE", - "scope": "UNCHANGED", - "confidentialityImpact": "HIGH", - "integrityImpact": "HIGH", - "availabilityImpact": "HIGH", - "baseScore": 9.8, - "baseSeverity": "CRITICAL" - }, - "exploitabilityScore": 3.9, - "impactScore": 5.9 - } - ], - "cvssMetricV2": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "cvssData": { - "version": "2.0", - "vectorString": "AV:N/AC:L/Au:N/C:P/I:P/A:P", - "accessVector": "NETWORK", - "accessComplexity": "LOW", - "authentication": "NONE", - "confidentialityImpact": "PARTIAL", - "integrityImpact": "PARTIAL", - "availabilityImpact": "PARTIAL", - "baseScore": 7.5 - }, - "baseSeverity": "HIGH", - "exploitabilityScore": 10.0, - "impactScore": 6.4, - "acInsufInfo": true, - "obtainAllPrivilege": false, - "obtainUserPrivilege": false, - "obtainOtherPrivilege": false, - "userInteractionRequired": false - } - ] - }, - "weaknesses": [ - { - "source": "nvd@nist.gov", - "type": "Primary", - "description": [ - { - "lang": "en", - "value": "CWE-20" - } - ] - } - ], - "configurations": [ - { - "operator": "AND", - "nodes": [ - { - "operator": "OR", - "negate": false, - "cpeMatch": [ - { - "vulnerable": true, - "criteria": "cpe:2.3:a:netapp:oncommand_unified_manager:*:*:*:*:*:*:*:*", - "versionStartIncluding": "7.2", - "versionEndIncluding": "7.3", - "matchCriteriaId": "A5949307-3E9B-441F-B008-81A0E0228DC0" - } - ] - }, - { - "operator": "OR", - "negate": false, - "cpeMatch": [ - { - "vulnerable": false, - "criteria": "cpe:2.3:o:linux:linux_kernel:-:*:*:*:*:*:*:*", - "matchCriteriaId": "703AF700-7A70-47E2-BC3A-7FD03B3CA9C1" - } - ] - } - ] - } - ], - "references": [ - { - "url": "https://security.netapp.com/advisory/ntap-20180523-0001/", - "source": "security-alert@netapp.com", - "tags": [ - "Patch", - "Vendor Advisory" - ] - } - ] - } -} diff --git a/pkg/process/v4/transformers/nvd/transform.go b/pkg/process/v4/transformers/nvd/transform.go deleted file mode 100644 index 809d5cf6..00000000 --- a/pkg/process/v4/transformers/nvd/transform.go +++ /dev/null @@ -1,109 +0,0 @@ -package nvd - -import ( - "fmt" - - "github.com/anchore/grype-db/internal" - "github.com/anchore/grype-db/pkg/data" - "github.com/anchore/grype-db/pkg/process/v4/transformers" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - "github.com/anchore/grype-db/pkg/provider/unmarshal/nvd" - grypeDB "github.com/anchore/grype/grype/db/v4" - "github.com/anchore/grype/grype/db/v4/namespace" -) - -const ( - // TODO: tech debt from a previous design - feed = "nvdv2" - group = "nvdv2:cves" -) - -func buildGrypeNamespace(feed, group string) (namespace.Namespace, error) { - if feed != "nvdv2" || group != "nvdv2:cves" { - return nil, fmt.Errorf("invalid source for feed=%s, group=%s", feed, group) - } - - ns, err := namespace.FromString("nvd:cpe") - - if err != nil { - return nil, err - } - - return ns, nil -} - -func Transform(vulnerability unmarshal.NVDVulnerability) ([]data.Entry, error) { - recordSource := fmt.Sprintf("%s:%s", feed, group) - grypeNamespace, err := buildGrypeNamespace(feed, group) - if err != nil { - return nil, err - } - - entryNamespace := grypeNamespace.String() - - uniquePkgs := findUniquePkgs(vulnerability.Configurations...) - - // extract all links - var links []string - for _, externalRefs := range vulnerability.References { - // TODO: should we capture other information here? - if externalRefs.URL != "" { - links = append(links, externalRefs.URL) - } - } - - // duplicate the vulnerabilities based on the set of unique packages the vulnerability is for - var allVulns []grypeDB.Vulnerability - for _, p := range uniquePkgs.All() { - matches := uniquePkgs.Matches(p) - cpes := internal.NewStringSet() - for _, m := range matches { - cpes.Add(grypeNamespace.Resolver().Normalize(m.Criteria)) - } - - // create vulnerability entry - allVulns = append(allVulns, grypeDB.Vulnerability{ - ID: vulnerability.ID, - VersionConstraint: buildConstraints(matches), - VersionFormat: "unknown", - PackageName: grypeNamespace.Resolver().Normalize(p.Product), - Namespace: entryNamespace, - CPEs: cpes.ToSlice(), - Fix: grypeDB.Fix{ - State: grypeDB.UnknownFixState, - }, - }) - } - - // create vulnerability metadata entry (a single entry keyed off of the vulnerability ID) - - allCVSS := vulnerability.CVSS() - metadata := grypeDB.VulnerabilityMetadata{ - ID: vulnerability.ID, - DataSource: "https://nvd.nist.gov/vuln/detail/" + vulnerability.ID, - Namespace: entryNamespace, - RecordSource: recordSource, - Severity: nvd.CvssSummaries(allCVSS).Sorted().Severity(), - URLs: links, - Description: vulnerability.Description(), - Cvss: getCvss(allCVSS...), - } - - return transformers.NewEntries(allVulns, metadata), nil -} - -func getCvss(cvss ...nvd.CvssSummary) []grypeDB.Cvss { - var results []grypeDB.Cvss - for _, c := range cvss { - results = append(results, grypeDB.Cvss{ - Version: c.Version, - Vector: c.Vector, - Metrics: grypeDB.CvssMetrics{ - BaseScore: c.BaseScore, - ExploitabilityScore: c.ExploitabilityScore, - ImpactScore: c.ImpactScore, - }, - }) - } - return results -} diff --git a/pkg/process/v4/transformers/nvd/transform_test.go b/pkg/process/v4/transformers/nvd/transform_test.go deleted file mode 100644 index 68ff578e..00000000 --- a/pkg/process/v4/transformers/nvd/transform_test.go +++ /dev/null @@ -1,257 +0,0 @@ -package nvd - -import ( - "os" - "testing" - - "github.com/go-test/deep" - "github.com/google/go-cmp/cmp" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - testUtils "github.com/anchore/grype-db/pkg/process/internal/tests" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v4" -) - -func TestUnmarshalNVDVulnerabilitiesEntries(t *testing.T) { - f, err := os.Open("test-fixtures/unmarshal-test.json") - require.NoError(t, err) - defer testUtils.CloseFile(f) - - entries, err := unmarshal.NvdVulnerabilityEntries(f) - require.NoError(t, err) - - assert.Len(t, entries, 1) -} - -func TestParseAllNVDVulnerabilityEntries(t *testing.T) { - - tests := []struct { - name string - numEntries int - fixture string - vulns []grypeDB.Vulnerability - metadata grypeDB.VulnerabilityMetadata - }{ - { - name: "AppVersionRange", - numEntries: 1, - fixture: "test-fixtures/version-range.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2018-5487", - PackageName: "oncommand_unified_manager", - VersionConstraint: ">= 7.2, <= 7.3", - VersionFormat: "unknown", // TODO: this should reference a format, yes? (not a string) - Namespace: "nvd:cpe", - CPEs: []string{"cpe:2.3:a:netapp:oncommand_unified_manager:*:*:*:*:*:*:*:*"}, - Fix: grypeDB.Fix{ - State: "unknown", - }, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2018-5487", - DataSource: "https://nvd.nist.gov/vuln/detail/CVE-2018-5487", - Namespace: "nvd:cpe", - RecordSource: "nvdv2:nvdv2:cves", - Severity: "Critical", - URLs: []string{"https://security.netapp.com/advisory/ntap-20180523-0001/"}, - Description: "NetApp OnCommand Unified Manager for Linux versions 7.2 through 7.3 ship with the Java Management Extension Remote Method Invocation (JMX RMI) service bound to the network, and are susceptible to unauthenticated remote code execution.", - Cvss: []grypeDB.Cvss{ - { - Metrics: grypeDB.NewCvssMetrics( - 7.5, - 10, - 6.4, - ), - Vector: "AV:N/AC:L/Au:N/C:P/I:P/A:P", - Version: "2.0", - }, - { - Metrics: grypeDB.NewCvssMetrics( - 9.8, - 3.9, - 5.9, - ), - Vector: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", - Version: "3.0", - }, - }, - }, - }, - { - name: "App+OS", - numEntries: 1, - fixture: "test-fixtures/single-package-multi-distro.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2018-1000222", - PackageName: "libgd", - VersionConstraint: "= 2.2.5", - VersionFormat: "unknown", // TODO: this should reference a format, yes? (not a string) - Namespace: "nvd:cpe", - CPEs: []string{"cpe:2.3:a:libgd:libgd:2.2.5:*:*:*:*:*:*:*"}, - Fix: grypeDB.Fix{ - State: "unknown", - }, - }, - // TODO: Question: should this match also the OS's? (as in the vulnerable_cpes list)... this seems wrong! - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2018-1000222", - DataSource: "https://nvd.nist.gov/vuln/detail/CVE-2018-1000222", - Namespace: "nvd:cpe", - RecordSource: "nvdv2:nvdv2:cves", - Severity: "High", - URLs: []string{"https://github.com/libgd/libgd/issues/447", "https://lists.debian.org/debian-lts-announce/2019/01/msg00028.html", "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/3CZ2QADQTKRHTGB2AHD7J4QQNDLBEMM6/", "https://security.gentoo.org/glsa/201903-18", "https://usn.ubuntu.com/3755-1/"}, - Description: "Libgd version 2.2.5 contains a Double Free Vulnerability vulnerability in gdImageBmpPtr Function that can result in Remote Code Execution . This attack appear to be exploitable via Specially Crafted Jpeg Image can trigger double free. This vulnerability appears to have been fixed in after commit ac16bdf2d41724b5a65255d4c28fb0ec46bc42f5.", - Cvss: []grypeDB.Cvss{ - { - Metrics: grypeDB.NewCvssMetrics( - 6.8, - 8.6, - 6.4, - ), - Vector: "AV:N/AC:M/Au:N/C:P/I:P/A:P", - Version: "2.0", - }, - { - Metrics: grypeDB.NewCvssMetrics( - 8.8, - 2.8, - 5.9, - ), - Vector: "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - Version: "3.0", - }, - }, - }, - }, - { - name: "AppCompoundVersionRange", - numEntries: 1, - fixture: "test-fixtures/compound-pkg.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2018-10189", - PackageName: "mautic", - VersionConstraint: ">= 1.0.0, <= 1.4.1 || >= 2.0.0, < 2.13.0", - VersionFormat: "unknown", - Namespace: "nvd:cpe", - CPEs: []string{"cpe:2.3:a:mautic:mautic:*:*:*:*:*:*:*:*"}, // note: entry was dedupicated - Fix: grypeDB.Fix{ - State: "unknown", - }, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2018-10189", - DataSource: "https://nvd.nist.gov/vuln/detail/CVE-2018-10189", - Namespace: "nvd:cpe", - RecordSource: "nvdv2:nvdv2:cves", - Severity: "High", - URLs: []string{"https://github.com/mautic/mautic/releases/tag/2.13.0"}, - Description: "An issue was discovered in Mautic 1.x and 2.x before 2.13.0. It is possible to systematically emulate tracking cookies per contact due to tracking the contact by their auto-incremented ID. Thus, a third party can manipulate the cookie value with +1 to systematically assume being tracked as each contact in Mautic. It is then possible to retrieve information about the contact through forms that have progressive profiling enabled.", - Cvss: []grypeDB.Cvss{ - { - Metrics: grypeDB.NewCvssMetrics( - 5, - 10, - 2.9, - ), - Vector: "AV:N/AC:L/Au:N/C:P/I:N/A:N", - Version: "2.0", - }, - { - Metrics: grypeDB.NewCvssMetrics( - 7.5, - 3.9, - 3.6, - ), - Vector: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", - Version: "3.0", - }, - }, - }, - }, - { - // we always keep the metadata even though there are no vulnerability entries for it - name: "InvalidCPE", - numEntries: 1, - fixture: "test-fixtures/invalid_cpe.json", - vulns: nil, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2015-8978", - Namespace: "nvd:cpe", - DataSource: "https://nvd.nist.gov/vuln/detail/CVE-2015-8978", - RecordSource: "nvdv2:nvdv2:cves", - Severity: "High", - URLs: []string{ - "http://cpansearch.perl.org/src/PHRED/SOAP-Lite-1.20/Changes", - "http://www.securityfocus.com/bid/94487", - }, - Description: "In Soap Lite (aka the SOAP::Lite extension for Perl) 1.14 and earlier, an example attack consists of defining 10 or more XML entities, each defined as consisting of 10 of the previous entity, with the document consisting of a single instance of the largest entity, which expands to one billion copies of the first entity. The amount of computer memory used for handling an external SOAP call would likely exceed that available to the process parsing the XML.", - Cvss: []grypeDB.Cvss{ - { - Metrics: grypeDB.NewCvssMetrics( - 5, - 10, - 2.9, - ), - Vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P", - Version: "2.0", - }, - { - Metrics: grypeDB.NewCvssMetrics( - 7.5, - 3.9, - 3.6, - ), - Vector: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", - Version: "3.0", - }, - }, - }, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - f, err := os.Open(test.fixture) - require.NoError(t, err) - t.Cleanup(func() { - assert.NoError(t, f.Close()) - }) - - entries, err := unmarshal.NvdVulnerabilityEntries(f) - require.NoError(t, err) - - var vulns []grypeDB.Vulnerability - for _, entry := range entries { - dataEntries, err := Transform(entry.Cve) - require.NoError(t, err) - - for _, entry := range dataEntries { - switch vuln := entry.Data.(type) { - case grypeDB.Vulnerability: - vulns = append(vulns, vuln) - case grypeDB.VulnerabilityMetadata: - // check metadata - if diff := deep.Equal(test.metadata, vuln); diff != nil { - for _, d := range diff { - t.Errorf("metadata diff: %+v", d) - } - } - default: - t.Fatalf("unexpected condition: data entry does not have a vulnerability or a metadata") - } - } - } - - if diff := cmp.Diff(test.vulns, vulns); diff != "" { - t.Errorf("vulnerabilities do not match (-want +got):\n%s", diff) - } - }) - } -} diff --git a/pkg/process/v4/transformers/nvd/unique_pkg.go b/pkg/process/v4/transformers/nvd/unique_pkg.go deleted file mode 100644 index 34621368..00000000 --- a/pkg/process/v4/transformers/nvd/unique_pkg.go +++ /dev/null @@ -1,115 +0,0 @@ -package nvd - -import ( - "fmt" - "strings" - - "github.com/umisama/go-cpe" - - "github.com/anchore/grype-db/internal/log" - "github.com/anchore/grype-db/pkg/process/internal/common" - "github.com/anchore/grype-db/pkg/provider/unmarshal/nvd" -) - -const ( - ANY = "*" - NA = "-" -) - -type pkgCandidate struct { - Product string - Vendor string - TargetSoftware string -} - -func (p pkgCandidate) String() string { - return fmt.Sprintf("%s|%s|%s", p.Vendor, p.Product, p.TargetSoftware) -} - -func newPkgCandidate(match nvd.CpeMatch) (*pkgCandidate, error) { - // we are only interested in packages that are vulnerable (not related to secondary match conditioning) - if !match.Vulnerable { - return nil, nil - } - - c, err := cpe.NewItemFromFormattedString(match.Criteria) - if err != nil { - return nil, fmt.Errorf("unable to create uniquePkgEntry from '%s': %w", match.Criteria, err) - } - - // we are only interested in applications, not hardware or operating systems - if c.Part() != cpe.Application { - return nil, nil - } - - return &pkgCandidate{ - Product: c.Product().String(), - Vendor: c.Vendor().String(), - TargetSoftware: c.TargetSw().String(), - }, nil -} - -func findUniquePkgs(cfgs ...nvd.Configuration) uniquePkgTracker { - set := newUniquePkgTracker() - for _, c := range cfgs { - _findUniquePkgs(set, c.Nodes...) - } - return set -} - -func _findUniquePkgs(set uniquePkgTracker, ns ...nvd.Node) { - if len(ns) == 0 { - return - } - for _, node := range ns { - for _, match := range node.CpeMatch { - candidate, err := newPkgCandidate(match) - if err != nil { - // Do not halt all execution because of being unable to create - // a PkgCandidate. This can happen when a CPE is invalid which - // could avoid creating a database - log.Debugf("unable processing uniquePkg: %v", err) - continue - } - if candidate != nil { - set.Add(*candidate, match) - } - } - } -} - -func buildConstraints(matches []nvd.CpeMatch) string { - constraints := make([]string, 0) - for _, match := range matches { - constraints = append(constraints, buildConstraint(match)) - } - return common.OrConstraints(constraints...) -} - -func buildConstraint(match nvd.CpeMatch) string { - constraints := make([]string, 0) - if match.VersionStartIncluding != nil && *match.VersionStartIncluding != "" { - constraints = append(constraints, fmt.Sprintf(">= %s", *match.VersionStartIncluding)) - } else if match.VersionStartExcluding != nil && *match.VersionStartExcluding != "" { - constraints = append(constraints, fmt.Sprintf("> %s", *match.VersionStartExcluding)) - } - - if match.VersionEndIncluding != nil && *match.VersionEndIncluding != "" { - constraints = append(constraints, fmt.Sprintf("<= %s", *match.VersionEndIncluding)) - } else if match.VersionEndExcluding != nil && *match.VersionEndExcluding != "" { - constraints = append(constraints, fmt.Sprintf("< %s", *match.VersionEndExcluding)) - } - - if len(constraints) == 0 { - c, err := cpe.NewItemFromFormattedString(match.Criteria) - if err != nil { - return "" - } - version := c.Version().String() - if version != ANY && version != NA { - constraints = append(constraints, fmt.Sprintf("= %s", version)) - } - } - - return strings.Join(constraints, ", ") -} diff --git a/pkg/process/v4/transformers/nvd/unique_pkg_test.go b/pkg/process/v4/transformers/nvd/unique_pkg_test.go deleted file mode 100644 index dc662c36..00000000 --- a/pkg/process/v4/transformers/nvd/unique_pkg_test.go +++ /dev/null @@ -1,353 +0,0 @@ -package nvd - -import ( - "testing" - - "github.com/sergi/go-diff/diffmatchpatch" - - "github.com/anchore/grype-db/pkg/provider/unmarshal/nvd" -) - -func newUniquePkgTrackerFromSlice(candidates []pkgCandidate) uniquePkgTracker { - set := newUniquePkgTracker() - for _, c := range candidates { - set[c] = nil - } - return set -} - -func TestFindUniquePkgs(t *testing.T) { - tests := []struct { - name string - nodes []nvd.Node - expected uniquePkgTracker - }{ - { - name: "simple-match", - nodes: []nvd.Node{ - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:2.2.0:*:*:*:*:target:*:*", - Vulnerable: true, - }, - }, - }, - }, - expected: newUniquePkgTrackerFromSlice( - []pkgCandidate{ - { - Product: "product", - Vendor: "vendor", - TargetSoftware: "target", - }, - }), - }, - { - name: "skip-hw", - nodes: []nvd.Node{ - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:h:vendor:product:2.2.0:*:*:*:*:target:*:*", - Vulnerable: true, - }, - }, - }, - }, - expected: newUniquePkgTrackerFromSlice([]pkgCandidate{}), - }, - { - name: "skip-os", - nodes: []nvd.Node{ - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:o:vendor:product:2.2.0:*:*:*:*:target:*:*", - Vulnerable: true, - }, - }, - }, - }, - expected: newUniquePkgTrackerFromSlice([]pkgCandidate{}), - }, - { - name: "duplicate-by-product", - nodes: []nvd.Node{ - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:productA:3.3.3:*:*:*:*:target:*:*", - Vulnerable: true, - }, - { - Criteria: "cpe:2.3:a:vendor:productB:2.2.0:*:*:*:*:target:*:*", - Vulnerable: true, - }, - }, - Operator: "OR", - }, - }, - expected: newUniquePkgTrackerFromSlice( - []pkgCandidate{ - { - Product: "productA", - Vendor: "vendor", - TargetSoftware: "target", - }, - { - Product: "productB", - Vendor: "vendor", - TargetSoftware: "target", - }, - }), - }, - { - name: "duplicate-by-target", - nodes: []nvd.Node{ - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:3.3.3:*:*:*:*:targetA:*:*", - Vulnerable: true, - }, - { - Criteria: "cpe:2.3:a:vendor:product:2.2.0:*:*:*:*:targetB:*:*", - Vulnerable: true, - }, - }, - Operator: "OR", - }, - }, - expected: newUniquePkgTrackerFromSlice( - []pkgCandidate{ - { - Product: "product", - Vendor: "vendor", - TargetSoftware: "targetA", - }, - { - Product: "product", - Vendor: "vendor", - TargetSoftware: "targetB", - }, - }), - }, - { - name: "duplicate-by-vendor", - nodes: []nvd.Node{ - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendorA:product:3.3.3:*:*:*:*:target:*:*", - Vulnerable: true, - }, - { - Criteria: "cpe:2.3:a:vendorB:product:2.2.0:*:*:*:*:target:*:*", - Vulnerable: true, - }, - }, - Operator: "OR", - }, - }, - expected: newUniquePkgTrackerFromSlice( - []pkgCandidate{ - { - Product: "product", - Vendor: "vendorA", - TargetSoftware: "target", - }, - { - Product: "product", - Vendor: "vendorB", - TargetSoftware: "target", - }, - }), - }, - { - name: "de-duplicate-case", - nodes: []nvd.Node{ - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:3.3.3:A:B:C:D:target:E:F", - Vulnerable: true, - }, - { - Criteria: "cpe:2.3:a:vendor:product:2.2.0:Q:R:S:T:target:U:V", - Vulnerable: true, - }, - }, - Operator: "OR", - }, - }, - expected: newUniquePkgTrackerFromSlice( - []pkgCandidate{ - { - Product: "product", - Vendor: "vendor", - TargetSoftware: "target", - }, - }), - }, - { - name: "duplicate-from-nested-nodes", - nodes: []nvd.Node{ - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendorB:product:2.2.0:*:*:*:*:target:*:*", - Vulnerable: true, - }, - }, - Operator: "OR", - }, - { - CpeMatch: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendorA:product:2.2.0:*:*:*:*:target:*:*", - Vulnerable: true, - }, - }, - Operator: "OR", - }, - }, - expected: newUniquePkgTrackerFromSlice( - []pkgCandidate{ - { - Product: "product", - Vendor: "vendorA", - TargetSoftware: "target", - }, - { - Product: "product", - Vendor: "vendorB", - TargetSoftware: "target", - }, - }), - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - actual := findUniquePkgs(nvd.Configuration{Nodes: test.nodes}) - missing, extra := test.expected.Diff(actual) - if len(missing) != 0 { - for _, c := range missing { - t.Errorf("missing candidate: %+v", c) - } - } - - if len(extra) != 0 { - for _, c := range extra { - t.Errorf("extra candidate: %+v", c) - } - } - }) - } - -} - -func strRef(s string) *string { - return &s -} - -func TestBuildConstraints(t *testing.T) { - tests := []struct { - name string - matches []nvd.CpeMatch - expected string - }{ - { - name: "Equals", - matches: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:2.2.0:*:*:*:*:target:*:*", - }, - }, - expected: "= 2.2.0", - }, - { - name: "VersionEndExcluding", - matches: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:*:*:*:*:*:target:*:*", - VersionEndExcluding: strRef("2.3.0"), - }, - }, - expected: "< 2.3.0", - }, - { - name: "VersionEndIncluding", - matches: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:*:*:*:*:*:target:*:*", - VersionEndIncluding: strRef("2.3.0"), - }, - }, - expected: "<= 2.3.0", - }, - { - name: "VersionStartExcluding", - matches: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:*:*:*:*:*:target:*:*", - VersionStartExcluding: strRef("2.3.0"), - }, - }, - expected: "> 2.3.0", - }, - { - name: "VersionStartIncluding", - matches: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:*:*:*:*:*:target:*:*", - VersionStartIncluding: strRef("2.3.0"), - }, - }, - expected: ">= 2.3.0", - }, - { - name: "Version Range", - matches: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:*:*:*:*:*:target:*:*", - VersionStartIncluding: strRef("2.3.0"), - VersionEndIncluding: strRef("2.5.0"), - }, - }, - expected: ">= 2.3.0, <= 2.5.0", - }, - { - name: "Multiple Version Ranges", - matches: []nvd.CpeMatch{ - { - Criteria: "cpe:2.3:a:vendor:product:*:*:*:*:*:target:*:*", - VersionStartIncluding: strRef("2.3.0"), - VersionEndIncluding: strRef("2.5.0"), - }, - { - Criteria: "cpe:2.3:a:vendor:product:*:*:*:*:*:target:*:*", - VersionStartExcluding: strRef("3.3.0"), - VersionEndExcluding: strRef("3.5.0"), - }, - }, - expected: ">= 2.3.0, <= 2.5.0 || > 3.3.0, < 3.5.0", - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - actual := buildConstraints(test.matches) - - if actual != test.expected { - dmp := diffmatchpatch.New() - diffs := dmp.DiffMain(actual, test.expected, true) - t.Errorf("Expected: '%s'", test.expected) - t.Errorf("Got : '%s'", actual) - t.Errorf("Diff : '%s'", dmp.DiffPrettyText(diffs)) - } - }) - } - -} diff --git a/pkg/process/v4/transformers/nvd/unique_pkg_tracker.go b/pkg/process/v4/transformers/nvd/unique_pkg_tracker.go deleted file mode 100644 index 2b7e405d..00000000 --- a/pkg/process/v4/transformers/nvd/unique_pkg_tracker.go +++ /dev/null @@ -1,64 +0,0 @@ -package nvd - -import ( - "sort" - - "github.com/anchore/grype-db/pkg/provider/unmarshal/nvd" -) - -type uniquePkgTracker map[pkgCandidate][]nvd.CpeMatch - -func newUniquePkgTracker() uniquePkgTracker { - return make(uniquePkgTracker) -} - -func (s uniquePkgTracker) Diff(other uniquePkgTracker) (missing []pkgCandidate, extra []pkgCandidate) { - for k := range s { - if !other.Contains(k) { - missing = append(missing, k) - } - } - - for k := range other { - if !s.Contains(k) { - extra = append(extra, k) - } - } - - return -} - -func (s uniquePkgTracker) Matches(i pkgCandidate) []nvd.CpeMatch { - return s[i] -} - -func (s uniquePkgTracker) Add(i pkgCandidate, match nvd.CpeMatch) { - if _, ok := s[i]; !ok { - s[i] = make([]nvd.CpeMatch, 0) - } - s[i] = append(s[i], match) -} - -func (s uniquePkgTracker) Remove(i pkgCandidate) { - delete(s, i) -} - -func (s uniquePkgTracker) Contains(i pkgCandidate) bool { - _, ok := s[i] - return ok -} - -func (s uniquePkgTracker) All() []pkgCandidate { - res := make([]pkgCandidate, len(s)) - idx := 0 - for k := range s { - res[idx] = k - idx++ - } - - sort.SliceStable(res, func(i, j int) bool { - return res[i].String() < res[j].String() - }) - - return res -} diff --git a/pkg/process/v4/transformers/os/test-fixtures/alpine-3.9.json b/pkg/process/v4/transformers/os/test-fixtures/alpine-3.9.json deleted file mode 100644 index b9d84395..00000000 --- a/pkg/process/v4/transformers/os/test-fixtures/alpine-3.9.json +++ /dev/null @@ -1,28 +0,0 @@ -[ - { - "Vulnerability": { - "CVSS": [], - "Description": "", - "FixedIn": [ - { - "Name": "xen", - "NamespaceName": "alpine:3.9", - "Version": "4.11.1-r0", - "VersionFormat": "apk" - } - ], - "Link": "http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-19967", - "Metadata": { - "NVD": { - "CVSSv2": { - "Score": 4.9, - "Vectors": "AV:L/AC:L/Au:N/C:N/I:N/A:C" - } - } - }, - "Name": "CVE-2018-19967", - "NamespaceName": "alpine:3.9", - "Severity": "Medium" - } - } -] \ No newline at end of file diff --git a/pkg/process/v4/transformers/os/test-fixtures/amazon-multiple-kernel-advisories.json b/pkg/process/v4/transformers/os/test-fixtures/amazon-multiple-kernel-advisories.json deleted file mode 100644 index 82f2b45b..00000000 --- a/pkg/process/v4/transformers/os/test-fixtures/amazon-multiple-kernel-advisories.json +++ /dev/null @@ -1,104 +0,0 @@ -[ - { - "Vulnerability": { - "Name": "ALAS-2021-1704", - "NamespaceName": "amzn:2", - "Description": "", - "Severity": "Medium", - "Metadata": { - "CVE": [ - { - "Name": "CVE-2021-3653" - }, - { - "Name": "CVE-2021-3656" - }, - { - "Name": "CVE-2021-3732" - } - ] - }, - "Link": "https://alas.aws.amazon.com/AL2/ALAS-2021-1704.html", - "FixedIn": [ - { - "Name": "kernel-headers", - "NamespaceName": "amzn:2", - "VersionFormat": "rpm", - "Version": "4.14.246-187.474.amzn2" - }, - { - "Name": "kernel", - "NamespaceName": "amzn:2", - "VersionFormat": "rpm", - "Version": "4.14.246-187.474.amzn2" - } - ] - } - }, - { - "Vulnerability": { - "Name": "ALASKERNEL-5.4-2022-007", - "NamespaceName": "amzn:2", - "Description": "", - "Severity": "Medium", - "Metadata": { - "CVE": [ - { - "Name": "CVE-2021-3753" - }, - { - "Name": "CVE-2021-40490" - } - ] - }, - "Link": "https://alas.aws.amazon.com/AL2/ALASKERNEL-5.4-2022-007.html", - "FixedIn": [ - { - "Name": "kernel-headers", - "NamespaceName": "amzn:2", - "VersionFormat": "rpm", - "Version": "5.4.144-69.257.amzn2" - }, - { - "Name": "kernel", - "NamespaceName": "amzn:2", - "VersionFormat": "rpm", - "Version": "5.4.144-69.257.amzn2" - } - ] - } - }, - { - "Vulnerability": { - "Name": "ALASKERNEL-5.10-2022-005", - "NamespaceName": "amzn:2", - "Description": "", - "Severity": "Medium", - "Metadata": { - "CVE": [ - { - "Name": "CVE-2021-3753" - }, - { - "Name": "CVE-2021-40490" - } - ] - }, - "Link": "https://alas.aws.amazon.com/AL2/ALASKERNEL-5.10-2022-005.html", - "FixedIn": [ - { - "Name": "kernel-headers", - "NamespaceName": "amzn:2", - "VersionFormat": "rpm", - "Version": "5.10.62-55.141.amzn2" - }, - { - "Name": "kernel", - "NamespaceName": "amzn:2", - "VersionFormat": "rpm", - "Version": "5.10.62-55.141.amzn2" - } - ] - } - } -] \ No newline at end of file diff --git a/pkg/process/v4/transformers/os/test-fixtures/amzn.json b/pkg/process/v4/transformers/os/test-fixtures/amzn.json deleted file mode 100644 index a862c32e..00000000 --- a/pkg/process/v4/transformers/os/test-fixtures/amzn.json +++ /dev/null @@ -1,49 +0,0 @@ -[ - { - "Vulnerability": { - "Description": "", - "FixedIn": [ - { - "Name": "389-ds-base", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - }, - { - "Name": "389-ds-base-debuginfo", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - }, - { - "Name": "389-ds-base-devel", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - }, - { - "Name": "389-ds-base-libs", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - }, - { - "Name": "389-ds-base-snmp", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - } - ], - "Link": "https://alas.aws.amazon.com/AL2/ALAS-2018-1106.html", - "Metadata": { - "CVE": [ - - {"Name": "CVE-2018-14648"} - ] - }, - "Name": "ALAS-2018-1106", - "NamespaceName": "amzn:2", - "Severity": "Medium" - } - } -] \ No newline at end of file diff --git a/pkg/process/v4/transformers/os/test-fixtures/debian-8-multiple-entries-for-same-package.json b/pkg/process/v4/transformers/os/test-fixtures/debian-8-multiple-entries-for-same-package.json deleted file mode 100644 index 5025b56e..00000000 --- a/pkg/process/v4/transformers/os/test-fixtures/debian-8-multiple-entries-for-same-package.json +++ /dev/null @@ -1,62 +0,0 @@ -[ - { - "Vulnerability": { - "CVSS": [], - "Description": "", - "FixedIn": [ - { - "Name": "rsyslog", - "NamespaceName": "debian:8", - "VendorAdvisory": { - "AdvisorySummary": [], - "NoAdvisory": false - }, - "Version": "5.7.4-1", - "VersionFormat": "dpkg" - } - ], - "Link": "https://security-tracker.debian.org/tracker/CVE-2011-4623", - "Metadata": { - "NVD": { - "CVSSv2": { - "Score": 2.1, - "Vectors": "AV:L/AC:L/Au:N/C:N/I:N/A:P" - } - } - }, - "Name": "CVE-2011-4623", - "NamespaceName": "debian:8", - "Severity": "Low" - } - }, - { - "Vulnerability": { - "CVSS": [], - "Description": "", - "FixedIn": [ - { - "Name": "rsyslog", - "NamespaceName": "debian:8", - "VendorAdvisory": { - "AdvisorySummary": [], - "NoAdvisory": false - }, - "Version": "3.18.6-1", - "VersionFormat": "dpkg" - } - ], - "Link": "https://security-tracker.debian.org/tracker/CVE-2008-5618", - "Metadata": { - "NVD": { - "CVSSv2": { - "Score": 5, - "Vectors": "AV:N/AC:L/Au:N/C:N/I:N/A:P" - } - } - }, - "Name": "CVE-2008-5618", - "NamespaceName": "debian:8", - "Severity": "Low" - } - } -] \ No newline at end of file diff --git a/pkg/process/v4/transformers/os/test-fixtures/debian-8.json b/pkg/process/v4/transformers/os/test-fixtures/debian-8.json deleted file mode 100644 index a758f13c..00000000 --- a/pkg/process/v4/transformers/os/test-fixtures/debian-8.json +++ /dev/null @@ -1,62 +0,0 @@ -[ - { - "Vulnerability": { - "CVSS": [], - "Description": "", - "FixedIn": [ - { - "Name": "asterisk", - "NamespaceName": "debian:8", - "VendorAdvisory": { - "AdvisorySummary": [], - "NoAdvisory": false - }, - "Version": "1:1.6.2.0~rc3-1", - "VersionFormat": "dpkg" - }, - { - "Name": "auth2db", - "NamespaceName": "debian:8", - "VendorAdvisory": { - "AdvisorySummary": [], - "NoAdvisory": false - }, - "Version": "0.2.5-2+dfsg-1", - "VersionFormat": "dpkg" - }, - { - "Name": "exaile", - "NamespaceName": "debian:8", - "VendorAdvisory": { - "AdvisorySummary": [], - "NoAdvisory": false - }, - "Version": "0.2.14+debian-2.2", - "VersionFormat": "dpkg" - }, - { - "Name": "wordpress", - "NamespaceName": "debian:8", - "VendorAdvisory": { - "AdvisorySummary": [], - "NoAdvisory": false - }, - "Version": "", - "VersionFormat": "dpkg" - } - ], - "Link": "https://security-tracker.debian.org/tracker/CVE-2008-7220", - "Metadata": { - "NVD": { - "CVSSv2": { - "Score": 7.5, - "Vectors": "AV:N/AC:L/Au:N/C:P/I:P/A:P" - } - } - }, - "Name": "CVE-2008-7220", - "NamespaceName": "debian:8", - "Severity": "High" - } - } -] \ No newline at end of file diff --git a/pkg/process/v4/transformers/os/test-fixtures/ol-8-modules.json b/pkg/process/v4/transformers/os/test-fixtures/ol-8-modules.json deleted file mode 100644 index f1d7372b..00000000 --- a/pkg/process/v4/transformers/os/test-fixtures/ol-8-modules.json +++ /dev/null @@ -1,36 +0,0 @@ -[ - { - "Vulnerability": { - "CVSS": [], - "Description": "A flaw was found in PostgreSQL, where some PostgreSQL extensions did not use the search_path safely in their installation script. This flaw allows an attacker with sufficient privileges to trick an administrator into executing a specially crafted script during the extension's installation or update. The highest threat from this vulnerability is to confidentiality, integrity, as well as system availability.", - "FixedIn": [ - { - "Module": "postgresql:10", - "Name": "postgresql", - "NamespaceName": "ol:8", - "Version": "0:10.14-1.module+el8.2.0+7801+be0fed80", - "VersionFormat": "rpm" - }, - { - "Module": "postgresql:12", - "Name": "postgresql", - "NamespaceName": "ol:8", - "Version": "0:12.5-1.module+el8.3.0+9042+664538f4", - "VersionFormat": "rpm" - }, - { - "Module": "postgresql:9.6", - "Name": "postgresql", - "NamespaceName": "ol:8", - "Version": "0:9.6.20-1.module+el8.3.0+8938+7f0e88b6", - "VersionFormat": "rpm" - } - ], - "Link": "https://access.redhat.com/security/cve/CVE-2020-14350", - "Metadata": {}, - "Name": "CVE-2020-14350", - "NamespaceName": "ol:8", - "Severity": "Medium" - } - } -] \ No newline at end of file diff --git a/pkg/process/v4/transformers/os/test-fixtures/ol-8.json b/pkg/process/v4/transformers/os/test-fixtures/ol-8.json deleted file mode 100644 index 09439ece..00000000 --- a/pkg/process/v4/transformers/os/test-fixtures/ol-8.json +++ /dev/null @@ -1,42 +0,0 @@ -[ - { - "Vulnerability": { - "CVSS": [], - "Description": "", - "FixedIn": [ - { - "Name": "libexif", - "NamespaceName": "ol:8", - "Version": "0:0.6.21-17.el8_2", - "VersionFormat": "rpm" - }, - { - "Name": "libexif-devel", - "NamespaceName": "ol:8", - "Version": "0:0.6.21-17.el8_2", - "VersionFormat": "rpm" - }, - { - "Name": "libexif-dummy", - "NamespaceName": "ol:8", - "Version": "None", - "VersionFormat": "rpm" - } - ], - "Link": "http://linux.oracle.com/errata/ELSA-2020-2550.html", - "Metadata": { - "CVE": [ - { - "Link": "http://linux.oracle.com/cve/CVE-2020-13112.html", - "Name": "CVE-2020-13112" - } - ], - "Issued": "2020-06-15", - "RefId": "ELSA-2020-2550" - }, - "Name": "ELSA-2020-2550", - "NamespaceName": "ol:8", - "Severity": "Medium" - } - } -] \ No newline at end of file diff --git a/pkg/process/v4/transformers/os/test-fixtures/rhel-8-modules.json b/pkg/process/v4/transformers/os/test-fixtures/rhel-8-modules.json deleted file mode 100644 index c0400ad5..00000000 --- a/pkg/process/v4/transformers/os/test-fixtures/rhel-8-modules.json +++ /dev/null @@ -1,75 +0,0 @@ -[ - { - "Vulnerability": { - "CVSS": [ - { - "base_metrics": { - "base_score": 7.1, - "base_severity": "High", - "exploitability_score": 1.2, - "impact_score": 5.9 - }, - "status": "verified", - "vector_string": "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:H", - "version": "3.1" - } - ], - "Description": "A flaw was found in PostgreSQL, where some PostgreSQL extensions did not use the search_path safely in their installation script. This flaw allows an attacker with sufficient privileges to trick an administrator into executing a specially crafted script during the extension's installation or update. The highest threat from this vulnerability is to confidentiality, integrity, as well as system availability.", - "FixedIn": [ - { - "Module": "postgresql:10", - "Name": "postgresql", - "NamespaceName": "rhel:8", - "VendorAdvisory": { - "AdvisorySummary": [ - { - "ID": "RHSA-2020:3669", - "Link": "https://access.redhat.com/errata/RHSA-2020:3669" - } - ], - "NoAdvisory": false - }, - "Version": "0:10.14-1.module+el8.2.0+7801+be0fed80", - "VersionFormat": "rpm" - }, - { - "Module": "postgresql:12", - "Name": "postgresql", - "NamespaceName": "rhel:8", - "VendorAdvisory": { - "AdvisorySummary": [ - { - "ID": "RHSA-2020:5620", - "Link": "https://access.redhat.com/errata/RHSA-2020:5620" - } - ], - "NoAdvisory": false - }, - "Version": "0:12.5-1.module+el8.3.0+9042+664538f4", - "VersionFormat": "rpm" - }, - { - "Module": "postgresql:9.6", - "Name": "postgresql", - "NamespaceName": "rhel:8", - "VendorAdvisory": { - "AdvisorySummary": [ - { - "ID": "RHSA-2020:5619", - "Link": "https://access.redhat.com/errata/RHSA-2020:5619" - } - ], - "NoAdvisory": false - }, - "Version": "0:9.6.20-1.module+el8.3.0+8938+7f0e88b6", - "VersionFormat": "rpm" - } - ], - "Link": "https://access.redhat.com/security/cve/CVE-2020-14350", - "Metadata": {}, - "Name": "CVE-2020-14350", - "NamespaceName": "rhel:8", - "Severity": "Medium" - } - } -] \ No newline at end of file diff --git a/pkg/process/v4/transformers/os/test-fixtures/rhel-8.json b/pkg/process/v4/transformers/os/test-fixtures/rhel-8.json deleted file mode 100644 index 2779708c..00000000 --- a/pkg/process/v4/transformers/os/test-fixtures/rhel-8.json +++ /dev/null @@ -1,57 +0,0 @@ -[ - { - "Vulnerability": { - "CVSS": [ - { - "base_metrics": { - "base_score": 8.8, - "base_severity": "High", - "exploitability_score": 2.8, - "impact_score": 5.9 - }, - "status": "verified", - "vector_string": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - "version": "3.1" - } - ], - "Description": "A flaw was found in Mozilla Firefox. A race condition can occur while running the nsDocShell destructor causing a use-after-free memory issue. The highest threat from this vulnerability is to data confidentiality and integrity as well as system availability.", - "FixedIn": [ - { - "Name": "firefox", - "NamespaceName": "rhel:8", - "VendorAdvisory": { - "AdvisorySummary": [ - { - "ID": "RHSA-2020:1341", - "Link": "https://access.redhat.com/errata/RHSA-2020:1341" - } - ], - "NoAdvisory": false - }, - "Version": "0:68.6.1-1.el8_1", - "VersionFormat": "rpm" - }, - { - "Name": "thunderbird", - "NamespaceName": "rhel:8", - "VendorAdvisory": { - "AdvisorySummary": [ - { - "ID": "RHSA-2020:1495", - "Link": "https://access.redhat.com/errata/RHSA-2020:1495" - } - ], - "NoAdvisory": false - }, - "Version": "0:68.7.0-1.el8_1", - "VersionFormat": "rpm" - } - ], - "Link": "https://access.redhat.com/security/cve/CVE-2020-6819", - "Metadata": {}, - "Name": "CVE-2020-6819", - "NamespaceName": "rhel:8", - "Severity": "Critical" - } - } -] \ No newline at end of file diff --git a/pkg/process/v4/transformers/os/test-fixtures/unmarshal-test.json b/pkg/process/v4/transformers/os/test-fixtures/unmarshal-test.json deleted file mode 100644 index edc6d25b..00000000 --- a/pkg/process/v4/transformers/os/test-fixtures/unmarshal-test.json +++ /dev/null @@ -1,104 +0,0 @@ -[ - { - "Vulnerability": { - "Description": "", - "FixedIn": [ - { - "Name": "389-ds-base", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - }, - { - "Name": "389-ds-base-debuginfo", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - }, - { - "Name": "389-ds-base-devel", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - }, - { - "Name": "389-ds-base-libs", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - }, - { - "Name": "389-ds-base-snmp", - "NamespaceName": "amzn:2", - "Version": "1.3.8.4-15.amzn2.0.1", - "VersionFormat": "rpm" - } - ], - "Link": "https://alas.aws.amazon.com/AL2/ALAS-2018-1106.html", - "Metadata": { - "CVE": [ - {"Name": "CVE-2018-14648"} - ] - }, - "Name": "ALAS-2018-1106", - "NamespaceName": "amzn:2", - "Severity": "Medium" - } - }, - { - "Vulnerability": { - "Description": "", - "FixedIn": [ - { - "Name": "kernel-livepatch-4.14.173-137.228", - "NamespaceName": "amzn:2", - "Version": "1.0-3.amzn2", - "VersionFormat": "rpm" - }, - { - "Name": "kernel-livepatch-4.14.173-137.228-debuginfo", - "NamespaceName": "amzn:2", - "Version": "1.0-3.amzn2", - "VersionFormat": "rpm" - } - ], - "Link": "https://alas.aws.amazon.com/AL2/ALASLIVEPATCH-2020-012.html", - "Metadata": { - "CVE": [ - {"Name": "CVE-2020-12657"} - ] - }, - "Name": "ALASLIVEPATCH-2020-012", - "NamespaceName": "amzn:2", - "Severity": "High" - } - }, - { - "Vulnerability": { - "Description": "", - "FixedIn": [ - { - "Name": "kernel-livepatch-4.14.171-136.231", - "NamespaceName": "amzn:2", - "Version": "1.0-5.amzn2", - "VersionFormat": "rpm" - }, - { - "Name": "kernel-livepatch-4.14.171-136.231-debuginfo", - "NamespaceName": "amzn:2", - "Version": "1.0-5.amzn2", - "VersionFormat": "rpm" - } - ], - "Link": "https://alas.aws.amazon.com/AL2/ALASLIVEPATCH-2020-011.html", - "Metadata": { - "CVE": [ - {"Name": "CVE-2020-12657"} - ] - }, - "Name": "ALASLIVEPATCH-2020-011", - "NamespaceName": "amzn:2", - "Severity": "High" - } - } -] \ No newline at end of file diff --git a/pkg/process/v4/transformers/os/transform.go b/pkg/process/v4/transformers/os/transform.go deleted file mode 100644 index 9a6b5c09..00000000 --- a/pkg/process/v4/transformers/os/transform.go +++ /dev/null @@ -1,218 +0,0 @@ -package os - -import ( - "fmt" - "strings" - - "github.com/anchore/grype-db/pkg/data" - "github.com/anchore/grype-db/pkg/process/internal/common" - "github.com/anchore/grype-db/pkg/process/v4/transformers" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v4" - "github.com/anchore/grype/grype/db/v4/namespace" - "github.com/anchore/grype/grype/distro" -) - -const ( - // TODO: tech debt from a previous design - feed = "vulnerabilities" -) - -func Transform(vulnerability unmarshal.OSVulnerability) ([]data.Entry, error) { - group := vulnerability.Vulnerability.NamespaceName - - var allVulns []grypeDB.Vulnerability - - recordSource := fmt.Sprintf("%s:%s", feed, group) - grypeNamespace, err := buildGrypeNamespace(feed, group) - if err != nil { - return nil, err - } - - entryNamespace := grypeNamespace.String() - vulnerability.Vulnerability.FixedIn = vulnerability.Vulnerability.FixedIn.FilterToHighestModularity() - - for idx, fixedInEntry := range vulnerability.Vulnerability.FixedIn { - // create vulnerability entry - allVulns = append(allVulns, grypeDB.Vulnerability{ - ID: vulnerability.Vulnerability.Name, - VersionConstraint: enforceConstraint(fixedInEntry.Version, fixedInEntry.VersionFormat, vulnerability.Vulnerability.Name), - VersionFormat: fixedInEntry.VersionFormat, - PackageName: grypeNamespace.Resolver().Normalize(fixedInEntry.Name), - Namespace: entryNamespace, - RelatedVulnerabilities: getRelatedVulnerabilities(vulnerability), - Fix: getFix(vulnerability, idx), - Advisories: getAdvisories(vulnerability, idx), - }) - } - - // create vulnerability metadata entry (a single entry keyed off of the vulnerability ID) - metadata := grypeDB.VulnerabilityMetadata{ - ID: vulnerability.Vulnerability.Name, - Namespace: entryNamespace, - DataSource: vulnerability.Vulnerability.Link, - RecordSource: recordSource, - Severity: vulnerability.Vulnerability.Severity, - URLs: getLinks(vulnerability), - Description: vulnerability.Vulnerability.Description, - Cvss: getCvss(vulnerability), - } - - return transformers.NewEntries(allVulns, metadata), nil -} - -func buildGrypeNamespace(feed, group string) (namespace.Namespace, error) { - if feed != "vulnerabilities" { - return nil, fmt.Errorf("unable to determine grype namespace for enterprise feed=%s, group=%s", feed, group) - } - - feedGroupComponents := strings.Split(group, ":") - - if len(feedGroupComponents) < 2 { - return nil, fmt.Errorf("unable to determine grype namespace for enterprise feed=%s, group=%s", feed, group) - } - - // Currently known enterprise feed groups are expected to be of the form {distroID}:{version} - feedGroupDistroID := feedGroupComponents[0] - d, ok := distro.IDMapping[feedGroupDistroID] - if !ok { - return nil, fmt.Errorf("unable to determine grype namespace for enterprise feed=%s, group=%s", feed, group) - } - - providerName := d.String() - - switch d { - case distro.OracleLinux: - providerName = "oracle" - case distro.AmazonLinux: - providerName = "amazon" - } - - ns, err := namespace.FromString(fmt.Sprintf("%s:distro:%s:%s", providerName, d.String(), feedGroupComponents[1])) - - if err != nil { - return nil, err - } - - return ns, nil -} - -func getLinks(entry unmarshal.OSVulnerability) []string { - // find all URLs related to the vulnerability - links := []string{entry.Vulnerability.Link} - if entry.Vulnerability.Metadata.CVE != nil { - for _, cve := range entry.Vulnerability.Metadata.CVE { - if cve.Link != "" { - links = append(links, cve.Link) - } - } - } - return links -} - -func getCvss(entry unmarshal.OSVulnerability) (cvss []grypeDB.Cvss) { - for _, vendorCvss := range entry.Vulnerability.CVSS { - cvss = append(cvss, grypeDB.Cvss{ - Version: vendorCvss.Version, - Vector: vendorCvss.VectorString, - Metrics: grypeDB.NewCvssMetrics( - vendorCvss.BaseMetrics.BaseScore, - vendorCvss.BaseMetrics.ExploitabilityScore, - vendorCvss.BaseMetrics.ImpactScore, - ), - VendorMetadata: transformers.VendorBaseMetrics{ - BaseSeverity: vendorCvss.BaseMetrics.BaseSeverity, - Status: vendorCvss.Status, - }, - }) - } - return cvss -} - -func getAdvisories(entry unmarshal.OSVulnerability, idx int) (advisories []grypeDB.Advisory) { - fixedInEntry := entry.Vulnerability.FixedIn[idx] - - for _, advisory := range fixedInEntry.VendorAdvisory.AdvisorySummary { - advisories = append(advisories, grypeDB.Advisory{ - ID: advisory.ID, - Link: advisory.Link, - }) - } - return advisories -} - -func getFix(entry unmarshal.OSVulnerability, idx int) grypeDB.Fix { - fixedInEntry := entry.Vulnerability.FixedIn[idx] - - var fixedInVersions []string - fixedInVersion := common.CleanFixedInVersion(fixedInEntry.Version) - if fixedInVersion != "" { - fixedInVersions = append(fixedInVersions, fixedInVersion) - } - - fixState := grypeDB.NotFixedState - if len(fixedInVersions) > 0 { - fixState = grypeDB.FixedState - } else if fixedInEntry.VendorAdvisory.NoAdvisory { - fixState = grypeDB.WontFixState - } - - return grypeDB.Fix{ - Versions: fixedInVersions, - State: fixState, - } -} - -func getRelatedVulnerabilities(entry unmarshal.OSVulnerability) (vulns []grypeDB.VulnerabilityReference) { - // associate related vulnerabilities from the NVD namespace - if strings.HasPrefix(entry.Vulnerability.Name, "CVE") { - vulns = append(vulns, grypeDB.VulnerabilityReference{ - ID: entry.Vulnerability.Name, - Namespace: "nvd:cpe", - }) - } - - // note: an example of multiple CVEs for a record is centos:5 RHSA-2007:0055 which maps to CVE-2007-0002 and CVE-2007-1466 - for _, ref := range entry.Vulnerability.Metadata.CVE { - vulns = append(vulns, grypeDB.VulnerabilityReference{ - ID: ref.Name, - Namespace: "nvd:cpe", - }) - } - return vulns -} - -func deriveConstraintFromFix(fixVersion, vulnerabilityID string) string { - constraint := fmt.Sprintf("< %s", fixVersion) - - if strings.HasPrefix(vulnerabilityID, "ALASKERNEL-") { - // Amazon advisories of the form ALASKERNEL-5.4-2023-048 should be interpreted as only applying to - // the 5.4.x kernel line since Amazon issue a separate advisory per affected line, thus the constraint - // should be >= 5.4, < {fix version}. In the future the vunnel schema for OS vulns should be enhanced - // to emit actual constraints rather than fixed-in entries (tracked in https://github.com/anchore/vunnel/issues/266) - // at which point this workaround in grype-db can be removed. - - components := strings.Split(vulnerabilityID, "-") - - if len(components) == 4 { - base := components[1] - constraint = fmt.Sprintf(">= %s, < %s", base, fixVersion) - } - } - - return constraint -} - -func enforceConstraint(constraint, format, vulnerabilityID string) string { - constraint = common.CleanConstraint(constraint) - if len(constraint) == 0 { - return "" - } - switch strings.ToLower(format) { - case "semver": - return common.EnforceSemVerConstraint(constraint) - default: - // the passed constraint is a fixed version - return deriveConstraintFromFix(constraint, vulnerabilityID) - } -} diff --git a/pkg/process/v4/transformers/os/transform_test.go b/pkg/process/v4/transformers/os/transform_test.go deleted file mode 100644 index 1e61445c..00000000 --- a/pkg/process/v4/transformers/os/transform_test.go +++ /dev/null @@ -1,757 +0,0 @@ -package os - -import ( - "os" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - testUtils "github.com/anchore/grype-db/pkg/process/internal/tests" - "github.com/anchore/grype-db/pkg/process/v4/transformers" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v4" -) - -func TestUnmarshalOSVulnerabilitiesEntries(t *testing.T) { - f, err := os.Open("test-fixtures/unmarshal-test.json") - require.NoError(t, err) - defer testUtils.CloseFile(f) - - entries, err := unmarshal.OSVulnerabilityEntries(f) - require.NoError(t, err) - - assert.Len(t, entries, 3) -} - -func TestParseVulnerabilitiesEntry(t *testing.T) { - tests := []struct { - name string - numEntries int - fixture string - vulns []grypeDB.Vulnerability - metadata grypeDB.VulnerabilityMetadata - feed, group string - }{ - { - name: "Amazon", - numEntries: 1, - fixture: "test-fixtures/amzn.json", - feed: "vulnerabilities", - group: "amzn:2", - vulns: []grypeDB.Vulnerability{ - { - ID: "ALAS-2018-1106", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2018-14648", - Namespace: "nvd:cpe", - }, - }, - PackageName: "389-ds-base", - Namespace: "amazon:distro:amazonlinux:2", - Fix: grypeDB.Fix{ - Versions: []string{"1.3.8.4-15.amzn2.0.1"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALAS-2018-1106", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2018-14648", - Namespace: "nvd:cpe", - }, - }, - PackageName: "389-ds-base-debuginfo", - Namespace: "amazon:distro:amazonlinux:2", - Fix: grypeDB.Fix{ - Versions: []string{"1.3.8.4-15.amzn2.0.1"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALAS-2018-1106", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2018-14648", - Namespace: "nvd:cpe", - }, - }, - PackageName: "389-ds-base-devel", - Namespace: "amazon:distro:amazonlinux:2", - Fix: grypeDB.Fix{ - Versions: []string{"1.3.8.4-15.amzn2.0.1"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALAS-2018-1106", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2018-14648", - Namespace: "nvd:cpe", - }, - }, - PackageName: "389-ds-base-libs", - Namespace: "amazon:distro:amazonlinux:2", - Fix: grypeDB.Fix{ - Versions: []string{"1.3.8.4-15.amzn2.0.1"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALAS-2018-1106", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2018-14648", - Namespace: "nvd:cpe", - }, - }, - PackageName: "389-ds-base-snmp", - Namespace: "amazon:distro:amazonlinux:2", - Fix: grypeDB.Fix{ - Versions: []string{"1.3.8.4-15.amzn2.0.1"}, - State: grypeDB.FixedState, - }, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "ALAS-2018-1106", - Namespace: "amazon:distro:amazonlinux:2", - DataSource: "https://alas.aws.amazon.com/AL2/ALAS-2018-1106.html", - RecordSource: "vulnerabilities:amzn:2", - Severity: "Medium", - URLs: []string{"https://alas.aws.amazon.com/AL2/ALAS-2018-1106.html"}, - }, - }, - { - name: "Debian", - numEntries: 1, - fixture: "test-fixtures/debian-8.json", - feed: "vulnerabilities", - group: "debian:8", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2008-7220", - PackageName: "asterisk", - VersionConstraint: "< 1:1.6.2.0~rc3-1", - VersionFormat: "dpkg", - Namespace: "debian:distro:debian:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2008-7220", - Namespace: "nvd:cpe", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"1:1.6.2.0~rc3-1"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "CVE-2008-7220", - PackageName: "auth2db", - VersionConstraint: "< 0.2.5-2+dfsg-1", - VersionFormat: "dpkg", - Namespace: "debian:distro:debian:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2008-7220", - Namespace: "nvd:cpe", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"0.2.5-2+dfsg-1"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "CVE-2008-7220", - PackageName: "exaile", - VersionConstraint: "< 0.2.14+debian-2.2", - VersionFormat: "dpkg", - Namespace: "debian:distro:debian:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2008-7220", - Namespace: "nvd:cpe", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"0.2.14+debian-2.2"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "CVE-2008-7220", - PackageName: "wordpress", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2008-7220", - Namespace: "nvd:cpe", - }, - }, - Fix: grypeDB.Fix{ - State: grypeDB.NotFixedState, - }, - VersionConstraint: "", - VersionFormat: "dpkg", - Namespace: "debian:distro:debian:8", - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2008-7220", - Namespace: "debian:distro:debian:8", - DataSource: "https://security-tracker.debian.org/tracker/CVE-2008-7220", - RecordSource: "vulnerabilities:debian:8", - Severity: "High", - URLs: []string{"https://security-tracker.debian.org/tracker/CVE-2008-7220"}, - Description: "", - }, - }, - { - name: "RHEL", - numEntries: 1, - fixture: "test-fixtures/rhel-8.json", - feed: "vulnerabilities", - group: "rhel:8", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2020-6819", - PackageName: "firefox", - VersionConstraint: "< 0:68.6.1-1.el8_1", - VersionFormat: "rpm", - Namespace: "redhat:distro:redhat:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2020-6819", - Namespace: "nvd:cpe", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"0:68.6.1-1.el8_1"}, - State: grypeDB.FixedState, - }, - Advisories: []grypeDB.Advisory{ - { - ID: "RHSA-2020:1341", - Link: "https://access.redhat.com/errata/RHSA-2020:1341", - }, - }, - }, - { - ID: "CVE-2020-6819", - PackageName: "thunderbird", - VersionConstraint: "< 0:68.7.0-1.el8_1", - VersionFormat: "rpm", - Namespace: "redhat:distro:redhat:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2020-6819", - Namespace: "nvd:cpe", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"0:68.7.0-1.el8_1"}, - State: grypeDB.FixedState, - }, - Advisories: []grypeDB.Advisory{ - { - ID: "RHSA-2020:1495", - Link: "https://access.redhat.com/errata/RHSA-2020:1495", - }, - }, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2020-6819", - DataSource: "https://access.redhat.com/security/cve/CVE-2020-6819", - Namespace: "redhat:distro:redhat:8", - RecordSource: "vulnerabilities:rhel:8", - Severity: "Critical", - URLs: []string{"https://access.redhat.com/security/cve/CVE-2020-6819"}, - Description: "A flaw was found in Mozilla Firefox. A race condition can occur while running the nsDocShell destructor causing a use-after-free memory issue. The highest threat from this vulnerability is to data confidentiality and integrity as well as system availability.", - Cvss: []grypeDB.Cvss{ - { - Version: "3.1", - Vector: "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - Metrics: grypeDB.NewCvssMetrics( - 8.8, - 2.8, - 5.9, - ), - VendorMetadata: transformers.VendorBaseMetrics{ - Status: "verified", - BaseSeverity: "High", - }, - }, - }, - }, - }, - { - name: "RHEL with modularity", - numEntries: 1, - fixture: "test-fixtures/rhel-8-modules.json", - feed: "vulnerabilities", - group: "rhel:8", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2020-14350", - PackageName: "postgresql", - VersionConstraint: "< 0:12.5-1.module+el8.3.0+9042+664538f4", - VersionFormat: "rpm", - Namespace: "redhat:distro:redhat:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2020-14350", - Namespace: "nvd:cpe", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"0:12.5-1.module+el8.3.0+9042+664538f4"}, - State: grypeDB.FixedState, - }, - Advisories: []grypeDB.Advisory{ - { - ID: "RHSA-2020:5620", - Link: "https://access.redhat.com/errata/RHSA-2020:5620", - }, - }, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2020-14350", - DataSource: "https://access.redhat.com/security/cve/CVE-2020-14350", - Namespace: "redhat:distro:redhat:8", - RecordSource: "vulnerabilities:rhel:8", - Severity: "Medium", - URLs: []string{"https://access.redhat.com/security/cve/CVE-2020-14350"}, - Description: "A flaw was found in PostgreSQL, where some PostgreSQL extensions did not use the search_path safely in their installation script. This flaw allows an attacker with sufficient privileges to trick an administrator into executing a specially crafted script during the extension's installation or update. The highest threat from this vulnerability is to confidentiality, integrity, as well as system availability.", - Cvss: []grypeDB.Cvss{ - { - Version: "3.1", - Vector: "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:H", - Metrics: grypeDB.NewCvssMetrics( - 7.1, - 1.2, - 5.9, - ), - VendorMetadata: transformers.VendorBaseMetrics{ - Status: "verified", - BaseSeverity: "High", - }, - }, - }, - }, - }, - { - name: "Alpine", - numEntries: 1, - fixture: "test-fixtures/alpine-3.9.json", - feed: "vulnerabilities", - group: "alpine:3.9", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2018-19967", - PackageName: "xen", - VersionConstraint: "< 4.11.1-r0", - VersionFormat: "apk", - Namespace: "alpine:distro:alpine:3.9", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2018-19967", - Namespace: "nvd:cpe", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"4.11.1-r0"}, - State: grypeDB.FixedState, - }, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2018-19967", - DataSource: "http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-19967", - Namespace: "alpine:distro:alpine:3.9", - RecordSource: "vulnerabilities:alpine:3.9", - Severity: "Medium", - URLs: []string{"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-19967"}, - Description: "", - }, - }, - { - name: "Oracle", - numEntries: 1, - fixture: "test-fixtures/ol-8.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "ELSA-2020-2550", - PackageName: "libexif", - VersionConstraint: "< 0:0.6.21-17.el8_2", - VersionFormat: "rpm", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2020-13112", - Namespace: "nvd:cpe", - }, - }, - Namespace: "oracle:distro:oraclelinux:8", - Fix: grypeDB.Fix{ - Versions: []string{"0:0.6.21-17.el8_2"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ELSA-2020-2550", - PackageName: "libexif-devel", - VersionConstraint: "< 0:0.6.21-17.el8_2", - VersionFormat: "rpm", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2020-13112", - Namespace: "nvd:cpe", - }, - }, - Namespace: "oracle:distro:oraclelinux:8", - Fix: grypeDB.Fix{ - Versions: []string{"0:0.6.21-17.el8_2"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ELSA-2020-2550", - PackageName: "libexif-dummy", - VersionConstraint: "", - VersionFormat: "rpm", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2020-13112", - Namespace: "nvd:cpe", - }, - }, - Namespace: "oracle:distro:oraclelinux:8", - Fix: grypeDB.Fix{ - Versions: nil, - State: grypeDB.NotFixedState, - }, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "ELSA-2020-2550", - DataSource: "http://linux.oracle.com/errata/ELSA-2020-2550.html", - Namespace: "oracle:distro:oraclelinux:8", - RecordSource: "vulnerabilities:ol:8", - Severity: "Medium", - URLs: []string{"http://linux.oracle.com/errata/ELSA-2020-2550.html", "http://linux.oracle.com/cve/CVE-2020-13112.html"}, - }, - }, - { - name: "Oracle Linux 8 with modularity", - numEntries: 1, - fixture: "test-fixtures/ol-8-modules.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2020-14350", - PackageName: "postgresql", - VersionConstraint: "< 0:12.5-1.module+el8.3.0+9042+664538f4", - VersionFormat: "rpm", - Namespace: "oracle:distro:oraclelinux:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2020-14350", - Namespace: "nvd:cpe", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"0:12.5-1.module+el8.3.0+9042+664538f4"}, - State: grypeDB.FixedState, - }, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2020-14350", - DataSource: "https://access.redhat.com/security/cve/CVE-2020-14350", - Namespace: "oracle:distro:oraclelinux:8", - RecordSource: "vulnerabilities:ol:8", - Severity: "Medium", - URLs: []string{"https://access.redhat.com/security/cve/CVE-2020-14350"}, - Description: "A flaw was found in PostgreSQL, where some PostgreSQL extensions did not use the search_path safely in their installation script. This flaw allows an attacker with sufficient privileges to trick an administrator into executing a specially crafted script during the extension's installation or update. The highest threat from this vulnerability is to confidentiality, integrity, as well as system availability.", - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - f, err := os.Open(test.fixture) - require.NoError(t, err) - t.Cleanup(func() { - assert.NoError(t, f.Close()) - }) - - entries, err := unmarshal.OSVulnerabilityEntries(f) - assert.NoError(t, err) - assert.Len(t, entries, 1) - - entry := entries[0] - - dataEntries, err := Transform(entry) - assert.NoError(t, err) - - var vulns []grypeDB.Vulnerability - for _, entry := range dataEntries { - switch vuln := entry.Data.(type) { - case grypeDB.Vulnerability: - vulns = append(vulns, vuln) - case grypeDB.VulnerabilityMetadata: - assert.Equal(t, test.metadata, vuln) - default: - t.Fatalf("unexpected condition: data entry does not have a vulnerability or a metadata: %+v", vuln) - } - } - - if diff := cmp.Diff(test.vulns, vulns); diff != "" { - t.Errorf("vulnerabilities do not match (-want +got):\n%s", diff) - } - - }) - } - -} - -func TestParseVulnerabilitiesAllEntries(t *testing.T) { - tests := []struct { - name string - numEntries int - fixture string - vulns []grypeDB.Vulnerability - }{ - { - name: "Debian", - numEntries: 2, - fixture: "test-fixtures/debian-8-multiple-entries-for-same-package.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2011-4623", - PackageName: "rsyslog", - VersionConstraint: "< 5.7.4-1", - VersionFormat: "dpkg", - Namespace: "debian:distro:debian:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2011-4623", - Namespace: "nvd:cpe", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"5.7.4-1"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "CVE-2008-5618", - PackageName: "rsyslog", - VersionConstraint: "< 3.18.6-1", - VersionFormat: "dpkg", - Namespace: "debian:distro:debian:8", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2008-5618", - Namespace: "nvd:cpe", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"3.18.6-1"}, - State: grypeDB.FixedState, - }, - }, - }, - }, - { - name: "Amazon", - numEntries: 3, - fixture: "test-fixtures/amazon-multiple-kernel-advisories.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "ALAS-2021-1704", - PackageName: "kernel-headers", - VersionConstraint: "< 4.14.246-187.474.amzn2", - VersionFormat: "rpm", - Namespace: "amazon:distro:amazonlinux:2", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2021-3653", - Namespace: "nvd:cpe", - }, - { - ID: "CVE-2021-3656", - Namespace: "nvd:cpe", - }, - { - ID: "CVE-2021-3732", - Namespace: "nvd:cpe", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"4.14.246-187.474.amzn2"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALAS-2021-1704", - PackageName: "kernel", - VersionConstraint: "< 4.14.246-187.474.amzn2", - VersionFormat: "rpm", - Namespace: "amazon:distro:amazonlinux:2", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2021-3653", - Namespace: "nvd:cpe", - }, - { - ID: "CVE-2021-3656", - Namespace: "nvd:cpe", - }, - { - ID: "CVE-2021-3732", - Namespace: "nvd:cpe", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"4.14.246-187.474.amzn2"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALASKERNEL-5.4-2022-007", - PackageName: "kernel-headers", - VersionConstraint: ">= 5.4, < 5.4.144-69.257.amzn2", - VersionFormat: "rpm", - Namespace: "amazon:distro:amazonlinux:2", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2021-3753", - Namespace: "nvd:cpe", - }, - { - ID: "CVE-2021-40490", - Namespace: "nvd:cpe", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"5.4.144-69.257.amzn2"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALASKERNEL-5.4-2022-007", - PackageName: "kernel", - VersionConstraint: ">= 5.4, < 5.4.144-69.257.amzn2", - VersionFormat: "rpm", - Namespace: "amazon:distro:amazonlinux:2", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2021-3753", - Namespace: "nvd:cpe", - }, - { - ID: "CVE-2021-40490", - Namespace: "nvd:cpe", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"5.4.144-69.257.amzn2"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALASKERNEL-5.10-2022-005", - PackageName: "kernel-headers", - VersionConstraint: ">= 5.10, < 5.10.62-55.141.amzn2", - VersionFormat: "rpm", - Namespace: "amazon:distro:amazonlinux:2", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2021-3753", - Namespace: "nvd:cpe", - }, - { - ID: "CVE-2021-40490", - Namespace: "nvd:cpe", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"5.10.62-55.141.amzn2"}, - State: grypeDB.FixedState, - }, - }, - { - ID: "ALASKERNEL-5.10-2022-005", - PackageName: "kernel", - VersionConstraint: ">= 5.10, < 5.10.62-55.141.amzn2", - VersionFormat: "rpm", - Namespace: "amazon:distro:amazonlinux:2", - RelatedVulnerabilities: []grypeDB.VulnerabilityReference{ - { - ID: "CVE-2021-3753", - Namespace: "nvd:cpe", - }, - { - ID: "CVE-2021-40490", - Namespace: "nvd:cpe", - }, - }, - Fix: grypeDB.Fix{ - Versions: []string{"5.10.62-55.141.amzn2"}, - State: grypeDB.FixedState, - }, - }, - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - f, err := os.Open(test.fixture) - require.NoError(t, err) - t.Cleanup(func() { - assert.NoError(t, f.Close()) - }) - - entries, err := unmarshal.OSVulnerabilityEntries(f) - assert.NoError(t, err) - assert.Len(t, entries, test.numEntries) - - var vulns []grypeDB.Vulnerability - for _, entry := range entries { - dataEntries, err := Transform(entry) - assert.NoError(t, err) - - for _, entry := range dataEntries { - switch vuln := entry.Data.(type) { - case grypeDB.Vulnerability: - vulns = append(vulns, vuln) - case grypeDB.VulnerabilityMetadata: - default: - t.Fatalf("unexpected condition: data entry does not have a vulnerability or a metadata: %+v", vuln) - } - } - } - - if diff := cmp.Diff(test.vulns, vulns); diff != "" { - t.Errorf("vulnerabilities do not match (-want +got):\n%s", diff) - } - }) - } -} diff --git a/pkg/process/v4/transformers/vulnerability_metadata.go b/pkg/process/v4/transformers/vulnerability_metadata.go deleted file mode 100644 index c40e9f6b..00000000 --- a/pkg/process/v4/transformers/vulnerability_metadata.go +++ /dev/null @@ -1,8 +0,0 @@ -package transformers - -// VendorBaseMetrics captures extra metrics that do not fit into a common CVSS -// struct, like Status and BaseSeverity -type VendorBaseMetrics struct { - BaseSeverity string `json:"base_severity"` - Status string `json:"status"` -} diff --git a/pkg/process/v4/writer.go b/pkg/process/v4/writer.go deleted file mode 100644 index cf2ab231..00000000 --- a/pkg/process/v4/writer.go +++ /dev/null @@ -1,142 +0,0 @@ -package v4 - -import ( - "crypto/sha256" - "fmt" - "path" - "path/filepath" - "strings" - "time" - - "github.com/spf13/afero" - - "github.com/anchore/grype-db/internal/file" - "github.com/anchore/grype-db/internal/log" - "github.com/anchore/grype-db/pkg/data" - "github.com/anchore/grype/grype/db/legacy/distribution" - grypeDB "github.com/anchore/grype/grype/db/v4" - grypeDBStore "github.com/anchore/grype/grype/db/v4/store" -) - -// TODO: add NVDNamespace const to grype.db package? -const nvdNamespace = "nvd:cpe" - -var _ data.Writer = (*writer)(nil) - -type writer struct { - dbPath string - store grypeDB.Store -} - -func NewWriter(directory string, dataAge time.Time) (data.Writer, error) { - dbPath := path.Join(directory, grypeDB.VulnerabilityStoreFileName) - theStore, err := grypeDBStore.New(dbPath, true) - if err != nil { - return nil, fmt.Errorf("unable to create writer: %w", err) - } - - if err := theStore.SetID(grypeDB.NewID(dataAge)); err != nil { - return nil, fmt.Errorf("unable to set DB ID: %w", err) - } - - return &writer{ - dbPath: dbPath, - store: theStore, - }, nil -} - -func (w writer) Write(entries ...data.Entry) error { - for _, entry := range entries { - if entry.DBSchemaVersion != grypeDB.SchemaVersion { - return fmt.Errorf("wrong schema version: want %+v got %+v", grypeDB.SchemaVersion, entry.DBSchemaVersion) - } - - switch row := entry.Data.(type) { - case grypeDB.Vulnerability: - if err := w.store.AddVulnerability(row); err != nil { - return fmt.Errorf("unable to write vulnerability to store: %w", err) - } - case grypeDB.VulnerabilityMetadata: - normalizeSeverity(&row, w.store) - if err := w.store.AddVulnerabilityMetadata(row); err != nil { - return fmt.Errorf("unable to write vulnerability metadata to store: %w", err) - } - case grypeDB.VulnerabilityMatchExclusion: - if err := w.store.AddVulnerabilityMatchExclusion(row); err != nil { - return fmt.Errorf("unable to write vulnerability match exclusion to store: %w", err) - } - default: - return fmt.Errorf("data entry is not of type vulnerability, vulnerability metadata, or exclusion: %T", row) - } - } - - return nil -} - -// metadataAndClose closes the database and returns its metadata. -// The reason this is a compound action is that getting the built time and -// schema version from the database is an operation on the open database, -// but the checksum must be computed after the database is compacted and closed. -func (w writer) metadataAndClose() (*distribution.Metadata, error) { - storeID, err := w.store.GetID() - if err != nil { - return nil, fmt.Errorf("failed to fetch store ID: %w", err) - } - w.store.Close() - hashStr, err := file.ContentDigest(afero.NewOsFs(), w.dbPath, sha256.New()) - if err != nil { - return nil, fmt.Errorf("failed to hash database file (%s): %w", w.dbPath, err) - } - - metadata := distribution.Metadata{ - Built: storeID.BuildTimestamp, - Version: storeID.SchemaVersion, - Checksum: "sha256:" + hashStr, - } - return &metadata, nil -} - -func (w writer) Close() error { - metadata, err := w.metadataAndClose() - if err != nil { - return err - } - - metadataPath := path.Join(filepath.Dir(w.dbPath), distribution.MetadataFileName) - if err = metadata.Write(metadataPath); err != nil { - return err - } - - log.WithFields("path", w.dbPath).Info("database created") - log.WithFields("path", metadataPath).Debug("database metadata created") - - return nil -} - -func normalizeSeverity(metadata *grypeDB.VulnerabilityMetadata, reader grypeDB.VulnerabilityMetadataStoreReader) { - metadata.Severity = string(data.ParseSeverity(metadata.Severity)) - if metadata.Severity != "" && strings.ToLower(metadata.Severity) != "unknown" { - return - } - if !strings.HasPrefix(strings.ToLower(metadata.ID), "cve") { - return - } - if strings.HasPrefix(metadata.Namespace, nvdNamespace) { - return - } - m, err := reader.GetVulnerabilityMetadata(metadata.ID, nvdNamespace) - if err != nil { - log.WithFields("id", metadata.ID, "error", err).Warn("error fetching vulnerability metadata from NVD namespace") - return - } - if m == nil { - log.WithFields("id", metadata.ID).Trace("unable to find vulnerability metadata from NVD namespace") - return - } - - newSeverity := string(data.ParseSeverity(m.Severity)) - if newSeverity != metadata.Severity { - log.WithFields("id", metadata.ID, "namespace", metadata.Namespace, "sev-from", metadata.Severity, "sev-to", newSeverity).Trace("overriding irrelevant severity with data from NVD record") - } - metadata.Severity = newSeverity -} diff --git a/pkg/process/v4/writer_test.go b/pkg/process/v4/writer_test.go deleted file mode 100644 index f3b9dfb5..00000000 --- a/pkg/process/v4/writer_test.go +++ /dev/null @@ -1,126 +0,0 @@ -package v4 - -import ( - "errors" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/anchore/grype-db/pkg/data" - grypeDB "github.com/anchore/grype/grype/db/v4" -) - -var _ grypeDB.VulnerabilityMetadataStoreReader = (*mockReader)(nil) - -type mockReader struct { - metadata *grypeDB.VulnerabilityMetadata - err error -} - -func newMockReader(sev string) *mockReader { - return &mockReader{ - metadata: &grypeDB.VulnerabilityMetadata{ - Severity: sev, - Namespace: "nvd", - }, - } -} - -func newDeadMockReader() *mockReader { - return &mockReader{ - err: errors.New("dead"), - } -} - -func (m mockReader) GetVulnerabilityMetadata(_, _ string) (*grypeDB.VulnerabilityMetadata, error) { - return m.metadata, m.err -} - -func (m mockReader) GetAllVulnerabilityMetadata() (*[]grypeDB.VulnerabilityMetadata, error) { - panic("implement me") -} - -func Test_normalizeSeverity(t *testing.T) { - - tests := []struct { - name string - initialSeverity string - namespace string - cveID string - reader grypeDB.VulnerabilityMetadataStoreReader - expected data.Severity - }{ - { - name: "missing severity set to Unknown", - initialSeverity: "", - namespace: "test", - reader: &mockReader{}, - expected: data.SeverityUnknown, - }, - { - name: "non-cve records metadata missing severity set to Unknown", - cveID: "GHSA-1234-1234-1234", - initialSeverity: "", - namespace: "test", - reader: newDeadMockReader(), // should not be used - expected: data.SeverityUnknown, - }, - { - name: "non-cve records metadata with severity set should not be overriden", - cveID: "GHSA-1234-1234-1234", - initialSeverity: "high", - namespace: "test", - reader: newMockReader("critical"), // should not be used - expected: data.SeverityHigh, - }, - { - name: "override empty severity from NVD", - initialSeverity: "", - namespace: "test", - reader: newMockReader("low"), - expected: data.SeverityLow, - }, - { - name: "override unknown severity from NVD", - initialSeverity: "unknown", - namespace: "test", - reader: newMockReader("low"), - expected: data.SeverityLow, - }, - { - name: "ignore record with severity already set", - initialSeverity: "Low", - namespace: "test", - reader: newMockReader("critical"), // should not be used - expected: data.SeverityLow, - }, - { - name: "ignore nvd records", - initialSeverity: "Low", - namespace: "nvdv2:cves", - reader: newDeadMockReader(), // should not be used - expected: data.SeverityLow, - }, - { - name: "db errors should not fail or modify the record other than normalizing unset value", - initialSeverity: "", - namespace: "test", - reader: newDeadMockReader(), - expected: data.SeverityUnknown, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - record := &grypeDB.VulnerabilityMetadata{ - ID: "cve-2020-0000", - Severity: tt.initialSeverity, - Namespace: tt.namespace, - } - if tt.cveID != "" { - record.ID = tt.cveID - } - normalizeSeverity(record, tt.reader) - assert.Equal(t, string(tt.expected), record.Severity) - }) - } -}