diff --git a/pkg/process/build.go b/pkg/process/build.go index 8a61fc1a..0e5eb315 100644 --- a/pkg/process/build.go +++ b/pkg/process/build.go @@ -9,16 +9,12 @@ import ( "github.com/anchore/grype-db/internal/log" "github.com/anchore/grype-db/pkg/data" - v1 "github.com/anchore/grype-db/pkg/process/v1" - v2 "github.com/anchore/grype-db/pkg/process/v2" 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" "github.com/anchore/grype-db/pkg/provider" "github.com/anchore/grype-db/pkg/provider/entry" "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDBv1 "github.com/anchore/grype/grype/db/v1" - grypeDBv2 "github.com/anchore/grype/grype/db/v2" grypeDBv3 "github.com/anchore/grype/grype/db/v3" grypeDBv4 "github.com/anchore/grype/grype/db/v4" grypeDBv5 "github.com/anchore/grype/grype/db/v5" @@ -93,10 +89,6 @@ func mergeOpeners(entries []openerEntry) <-chan entry.Opener { func getProcessors(cfg BuildConfig) ([]data.Processor, error) { switch cfg.SchemaVersion { - case grypeDBv1.SchemaVersion: - return v1.Processors(), nil - case grypeDBv2.SchemaVersion: - return v2.Processors(), nil case grypeDBv3.SchemaVersion: return v3.Processors(), nil case grypeDBv4.SchemaVersion: @@ -110,10 +102,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 grypeDBv1.SchemaVersion: - return v1.NewWriter(directory, dataAge) - case grypeDBv2.SchemaVersion: - return v2.NewWriter(directory, dataAge) case grypeDBv3.SchemaVersion: return v3.NewWriter(directory, dataAge) case grypeDBv4.SchemaVersion: diff --git a/pkg/process/v1/processors.go b/pkg/process/v1/processors.go deleted file mode 100644 index 3f05d004..00000000 --- a/pkg/process/v1/processors.go +++ /dev/null @@ -1,17 +0,0 @@ -package v1 - -import ( - "github.com/anchore/grype-db/pkg/data" - "github.com/anchore/grype-db/pkg/process/processors" - "github.com/anchore/grype-db/pkg/process/v1/transformers/github" - "github.com/anchore/grype-db/pkg/process/v1/transformers/nvd" - "github.com/anchore/grype-db/pkg/process/v1/transformers/os" -) - -func Processors() []data.Processor { - return []data.Processor{ - processors.NewGitHubProcessor(github.Transform), - processors.NewNVDProcessor(nvd.Transform), - processors.NewOSProcessor(os.Transform), - } -} diff --git a/pkg/process/v1/transformers/entry.go b/pkg/process/v1/transformers/entry.go deleted file mode 100644 index 172f7aa9..00000000 --- a/pkg/process/v1/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/v1" -) - -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/v1/transformers/github/test-fixtures/github-github-npm-0.json b/pkg/process/v1/transformers/github/test-fixtures/github-github-npm-0.json deleted file mode 100644 index b0a7d1e9..00000000 --- a/pkg/process/v1/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/v1/transformers/github/test-fixtures/github-github-python-0.json b/pkg/process/v1/transformers/github/test-fixtures/github-github-python-0.json deleted file mode 100644 index ad14aa60..00000000 --- a/pkg/process/v1/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/v1/transformers/github/test-fixtures/github-github-python-1.json b/pkg/process/v1/transformers/github/test-fixtures/github-github-python-1.json deleted file mode 100644 index bfa84922..00000000 --- a/pkg/process/v1/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/v1/transformers/github/test-fixtures/github-withdrawn.json b/pkg/process/v1/transformers/github/test-fixtures/github-withdrawn.json deleted file mode 100644 index 04995e38..00000000 --- a/pkg/process/v1/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/v1/transformers/github/test-fixtures/multiple-fixed-in-names.json b/pkg/process/v1/transformers/github/test-fixtures/multiple-fixed-in-names.json deleted file mode 100644 index ac1ef982..00000000 --- a/pkg/process/v1/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/v1/transformers/github/transform.go b/pkg/process/v1/transformers/github/transform.go deleted file mode 100644 index 05593bb1..00000000 --- a/pkg/process/v1/transformers/github/transform.go +++ /dev/null @@ -1,65 +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/v1/transformers" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v1" -) - -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 != nil { - return nil, nil - } - - recordSource := grypeDB.RecordSource(feed, vulnerability.Advisory.Namespace) - - // 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 _, advisory := range vulnerability.Advisory.FixedIn { - constraint := common.EnforceSemVerConstraint(advisory.Range) - - var versionFormat string - switch vulnerability.Advisory.Namespace { - case "github:python": - versionFormat = "python" - default: - versionFormat = "unknown" - } - - // create vulnerability entry - vuln := grypeDB.Vulnerability{ - ID: vulnerability.Advisory.GhsaID, - RecordSource: recordSource, - VersionConstraint: constraint, - VersionFormat: versionFormat, // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: vulnerability.Advisory.CVE, - PackageName: advisory.Name, - Namespace: advisory.Namespace, - FixedInVersion: common.CleanFixedInVersion(advisory.Identifier), - } - - allVulns = append(allVulns, vuln) - } - - // create vulnerability metadata entry (a single entry keyed off of the vulnerability ID) - metadata := grypeDB.VulnerabilityMetadata{ - ID: vulnerability.Advisory.GhsaID, - RecordSource: recordSource, - Severity: vulnerability.Advisory.Severity, - Links: []string{vulnerability.Advisory.URL}, - Description: vulnerability.Advisory.Summary, - } - - return transformers.NewEntries(allVulns, metadata), nil -} diff --git a/pkg/process/v1/transformers/github/transform_test.go b/pkg/process/v1/transformers/github/transform_test.go deleted file mode 100644 index 9e8ab758..00000000 --- a/pkg/process/v1/transformers/github/transform_test.go +++ /dev/null @@ -1,168 +0,0 @@ -package github - -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/v1" -) - -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", - RecordSource: "github:python", - VersionConstraint: ">=4.0,<4.3.12", - VersionFormat: "python", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2017-5524"}, - PackageName: "Plone", - Namespace: "github:python", - FixedInVersion: "4.3.12", - }, - { - ID: "GHSA-p5wr-vp8g-q5p4", - RecordSource: "github:python", - VersionConstraint: ">=5.1a1,<5.1b1", - VersionFormat: "python", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2017-5524"}, - PackageName: "Plone", - Namespace: "github:python", - FixedInVersion: "5.1b1", - }, - { - ID: "GHSA-p5wr-vp8g-q5p4", - RecordSource: "github:python", - VersionConstraint: ">=5.0rc1,<5.0.7", - VersionFormat: "python", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2017-5524"}, - PackageName: "Plone", - Namespace: "github:python", - FixedInVersion: "5.0.7", - }, - } - - expectedMetadata := grypeDB.VulnerabilityMetadata{ - ID: "GHSA-p5wr-vp8g-q5p4", - RecordSource: "github:python", - Severity: "Medium", - Links: []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) - 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, 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)) - - assert.ElementsMatch(t, expectedVulns, vulns) - -} - -func TestDefaultVersionFormatNpmGitHubEntry(t *testing.T) { - expectedVulns := []grypeDB.Vulnerability{ - { - ID: "GHSA-vc9j-fhvv-8vrf", - RecordSource: "github:npm", - VersionConstraint: "<=0.2.0-prerelease.20200709173451", - VersionFormat: "unknown", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2020-14000"}, - PackageName: "scratch-vm", - Namespace: "github:npm", - FixedInVersion: "0.2.0-prerelease.20200714185213", - }, - } - - expectedMetadata := grypeDB.VulnerabilityMetadata{ - ID: "GHSA-vc9j-fhvv-8vrf", - RecordSource: "github:npm", - Severity: "High", - Links: []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) - 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, 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)) - - assert.ElementsMatch(t, expectedVulns, vulns) -} - -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/v1/transformers/nvd/test-fixtures/compound-pkg.json b/pkg/process/v1/transformers/nvd/test-fixtures/compound-pkg.json deleted file mode 100644 index 8e658dcd..00000000 --- a/pkg/process/v1/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/v1/transformers/nvd/test-fixtures/invalid_cpe.json b/pkg/process/v1/transformers/nvd/test-fixtures/invalid_cpe.json deleted file mode 100644 index eac2ebd4..00000000 --- a/pkg/process/v1/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/v1/transformers/nvd/test-fixtures/single-package-multi-distro.json b/pkg/process/v1/transformers/nvd/test-fixtures/single-package-multi-distro.json deleted file mode 100644 index ed108475..00000000 --- a/pkg/process/v1/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/v1/transformers/nvd/test-fixtures/unmarshal-test.json b/pkg/process/v1/transformers/nvd/test-fixtures/unmarshal-test.json deleted file mode 100644 index 2dc698fa..00000000 --- a/pkg/process/v1/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/v1/transformers/nvd/test-fixtures/version-range.json b/pkg/process/v1/transformers/nvd/test-fixtures/version-range.json deleted file mode 100644 index 3df5b86d..00000000 --- a/pkg/process/v1/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/v1/transformers/nvd/transform.go b/pkg/process/v1/transformers/nvd/transform.go deleted file mode 100644 index aa0d3924..00000000 --- a/pkg/process/v1/transformers/nvd/transform.go +++ /dev/null @@ -1,110 +0,0 @@ -package nvd - -import ( - "strings" - - "github.com/anchore/grype-db/internal" - "github.com/anchore/grype-db/pkg/data" - "github.com/anchore/grype-db/pkg/process/v1/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/v1" -) - -const ( - // TODO: tech debt from a previous design - feed = "nvdv2" - group = "nvdv2:cves" -) - -func Transform(vulnerability unmarshal.NVDVulnerability) ([]data.Entry, error) { - var allVulns []grypeDB.Vulnerability - - recordSource := grypeDB.RecordSource(feed, group) - - 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 - for _, p := range uniquePkgs.All() { - matches := uniquePkgs.Matches(p) - cpes := internal.NewStringSet() - for _, m := range matches { - cpes.Add(m.Criteria) - } - - // create vulnerability entry - vuln := grypeDB.Vulnerability{ - ID: vulnerability.ID, - RecordSource: recordSource, - VersionConstraint: buildConstraints(matches), - VersionFormat: "unknown", // TODO: derive this from the target software - PackageName: p.Product, - Namespace: "nvd", // should the vendor be here? or in other metadata? - ProxyVulnerabilities: []string{}, - CPEs: cpes.ToSlice(), - } - - allVulns = append(allVulns, vuln) - } - - // If all the CPEs are invalid and no vulnerabilities were generated then there is no point - // in creating metadata, so just return - if len(allVulns) == 0 { - return nil, nil - } - - // create vulnerability metadata entry (a single entry keyed off of the vulnerability ID) - allCVSS := vulnerability.CVSS() - - metadata := grypeDB.VulnerabilityMetadata{ - ID: vulnerability.ID, - RecordSource: recordSource, - Severity: nvd.CvssSummaries(allCVSS).Sorted().Severity(), - Links: links, - Description: vulnerability.Description(), - } - - for _, c := range allCVSS { - if strings.HasPrefix(c.Version, "2.") { - newCvss := &grypeDB.Cvss{ - BaseScore: c.BaseScore, - Vector: c.Vector, - } - if c.ExploitabilityScore != nil { - newCvss.ExploitabilityScore = *c.ExploitabilityScore - } - if c.ImpactScore != nil { - newCvss.ImpactScore = *c.ImpactScore - } - metadata.CvssV2 = newCvss - break - } - } - - for _, c := range allCVSS { - if strings.HasPrefix(c.Version, "3.") { - newCvss := &grypeDB.Cvss{ - BaseScore: c.BaseScore, - Vector: c.Vector, - } - if c.ExploitabilityScore != nil { - newCvss.ExploitabilityScore = *c.ExploitabilityScore - } - if c.ImpactScore != nil { - newCvss.ImpactScore = *c.ImpactScore - } - metadata.CvssV3 = newCvss - break - } - } - - return transformers.NewEntries(allVulns, metadata), nil -} diff --git a/pkg/process/v1/transformers/nvd/transform_test.go b/pkg/process/v1/transformers/nvd/transform_test.go deleted file mode 100644 index cecb2f98..00000000 --- a/pkg/process/v1/transformers/nvd/transform_test.go +++ /dev/null @@ -1,192 +0,0 @@ -package nvd - -import ( - "os" - "testing" - - "github.com/go-test/deep" - "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/v1" -) - -const recordSource = "nvdv2:cves" - -func TestUnmarshalVulnerabilitiesEntries(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 TestParseVulnerabilitiesAllEntries(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", - RecordSource: recordSource, - PackageName: "oncommand_unified_manager", - VersionConstraint: ">= 7.2, <= 7.3", - VersionFormat: "unknown", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "nvd", - CPEs: []string{"cpe:2.3:a:netapp:oncommand_unified_manager:*:*:*:*:*:*:*:*"}, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2018-5487", - RecordSource: recordSource, - Severity: "Critical", - Links: []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.", - CvssV2: &grypeDB.Cvss{ - BaseScore: 7.5, - ExploitabilityScore: 10, - ImpactScore: 6.4, - Vector: "AV:N/AC:L/Au:N/C:P/I:P/A:P", - }, - CvssV3: &grypeDB.Cvss{ - BaseScore: 9.8, - ExploitabilityScore: 3.9, - ImpactScore: 5.9, - Vector: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", - }, - }, - }, - { - name: "App+OS", - numEntries: 1, - fixture: "test-fixtures/single-package-multi-distro.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2018-1000222", - RecordSource: recordSource, - PackageName: "libgd", - VersionConstraint: "= 2.2.5", - VersionFormat: "unknown", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "nvd", - CPEs: []string{"cpe:2.3:a:libgd:libgd:2.2.5:*:*:*:*:*:*:*"}, - }, - // 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", - RecordSource: recordSource, - Severity: "High", - Links: []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.", - CvssV2: &grypeDB.Cvss{ - BaseScore: 6.8, - ExploitabilityScore: 8.6, - ImpactScore: 6.4, - Vector: "AV:N/AC:M/Au:N/C:P/I:P/A:P", - }, - CvssV3: &grypeDB.Cvss{ - BaseScore: 8.8, - ExploitabilityScore: 2.8, - ImpactScore: 5.9, - Vector: "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - }, - }, - }, - { - name: "AppCompoundVersionRange", - numEntries: 1, - fixture: "test-fixtures/compound-pkg.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2018-10189", - RecordSource: recordSource, - PackageName: "mautic", - VersionConstraint: ">= 1.0.0, <= 1.4.1 || >= 2.0.0, < 2.13.0", - VersionFormat: "unknown", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "nvd", - CPEs: []string{"cpe:2.3:a:mautic:mautic:*:*:*:*:*:*:*:*"}, // note: entry was dedupicated - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2018-10189", - RecordSource: recordSource, - Severity: "High", - Links: []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.", - CvssV2: &grypeDB.Cvss{ - BaseScore: 5, - ExploitabilityScore: 10, - ImpactScore: 2.9, - Vector: "AV:N/AC:L/Au:N/C:P/I:N/A:N", - }, - CvssV3: &grypeDB.Cvss{ - BaseScore: 7.5, - ExploitabilityScore: 3.9, - ImpactScore: 3.6, - Vector: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", - }, - }, - }, - { - name: "InvalidCPE", - numEntries: 1, - fixture: "test-fixtures/invalid_cpe.json", - vulns: []grypeDB.Vulnerability{}, - metadata: grypeDB.VulnerabilityMetadata{}, - }, - } - - 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) - assert.NoError(t, err) - - var vulns []grypeDB.Vulnerability - for _, entry := range entries { - dataEntries, err := Transform(entry.Cve) - assert.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") - } - } - - } - - assert.ElementsMatch(t, test.vulns, vulns) - }) - } -} diff --git a/pkg/process/v1/transformers/nvd/unique_pkg.go b/pkg/process/v1/transformers/nvd/unique_pkg.go deleted file mode 100644 index 34621368..00000000 --- a/pkg/process/v1/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/v1/transformers/nvd/unique_pkg_test.go b/pkg/process/v1/transformers/nvd/unique_pkg_test.go deleted file mode 100644 index beb050fc..00000000 --- a/pkg/process/v1/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: %q", test.expected) - t.Errorf("Got : %q", actual) - t.Errorf("Diff : %q", dmp.DiffPrettyText(diffs)) - } - }) - } - -} diff --git a/pkg/process/v1/transformers/nvd/unique_pkg_tracker.go b/pkg/process/v1/transformers/nvd/unique_pkg_tracker.go deleted file mode 100644 index 2b7e405d..00000000 --- a/pkg/process/v1/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/v1/transformers/os/test-fixtures/alpine-3.9.json b/pkg/process/v1/transformers/os/test-fixtures/alpine-3.9.json deleted file mode 100644 index b9d84395..00000000 --- a/pkg/process/v1/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/v1/transformers/os/test-fixtures/amazon-multiple-kernel-advisories.json b/pkg/process/v1/transformers/os/test-fixtures/amazon-multiple-kernel-advisories.json deleted file mode 100644 index 82f2b45b..00000000 --- a/pkg/process/v1/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/v1/transformers/os/test-fixtures/amzn.json b/pkg/process/v1/transformers/os/test-fixtures/amzn.json deleted file mode 100644 index a862c32e..00000000 --- a/pkg/process/v1/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/v1/transformers/os/test-fixtures/debian-8-multiple-entries-for-same-package.json b/pkg/process/v1/transformers/os/test-fixtures/debian-8-multiple-entries-for-same-package.json deleted file mode 100644 index 5025b56e..00000000 --- a/pkg/process/v1/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/v1/transformers/os/test-fixtures/debian-8.json b/pkg/process/v1/transformers/os/test-fixtures/debian-8.json deleted file mode 100644 index a758f13c..00000000 --- a/pkg/process/v1/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/v1/transformers/os/test-fixtures/ol-8-modules.json b/pkg/process/v1/transformers/os/test-fixtures/ol-8-modules.json deleted file mode 100644 index f1d7372b..00000000 --- a/pkg/process/v1/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/v1/transformers/os/test-fixtures/ol-8.json b/pkg/process/v1/transformers/os/test-fixtures/ol-8.json deleted file mode 100644 index 09439ece..00000000 --- a/pkg/process/v1/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/v1/transformers/os/test-fixtures/rhel-8-modules.json b/pkg/process/v1/transformers/os/test-fixtures/rhel-8-modules.json deleted file mode 100644 index c0400ad5..00000000 --- a/pkg/process/v1/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/v1/transformers/os/test-fixtures/rhel-8.json b/pkg/process/v1/transformers/os/test-fixtures/rhel-8.json deleted file mode 100644 index 2779708c..00000000 --- a/pkg/process/v1/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/v1/transformers/os/test-fixtures/unmarshal-test.json b/pkg/process/v1/transformers/os/test-fixtures/unmarshal-test.json deleted file mode 100644 index edc6d25b..00000000 --- a/pkg/process/v1/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/v1/transformers/os/transform.go b/pkg/process/v1/transformers/os/transform.go deleted file mode 100644 index df8c3b24..00000000 --- a/pkg/process/v1/transformers/os/transform.go +++ /dev/null @@ -1,118 +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/v1/transformers" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v1" -) - -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) - 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 _, advisory := range vulnerability.Vulnerability.FixedIn { - // create vulnerability entry - vuln := grypeDB.Vulnerability{ - ID: vulnerability.Vulnerability.Name, - RecordSource: recordSource, - VersionConstraint: enforceConstraint(advisory.Version, advisory.VersionFormat, vulnerability.Vulnerability.Name), - VersionFormat: advisory.VersionFormat, - PackageName: advisory.Name, - Namespace: advisory.NamespaceName, - ProxyVulnerabilities: []string{}, - FixedInVersion: common.CleanFixedInVersion(advisory.Version), - } - - // associate related vulnerabilities - // 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 vulnerability.Vulnerability.Metadata.CVE { - vuln.ProxyVulnerabilities = append(vuln.ProxyVulnerabilities, ref.Name) - } - - allVulns = append(allVulns, vuln) - } - - var cvssV2 *grypeDB.Cvss - if vulnerability.Vulnerability.Metadata.NVD.CVSSv2.Vectors != "" { - cvssV2 = &grypeDB.Cvss{ - BaseScore: vulnerability.Vulnerability.Metadata.NVD.CVSSv2.Score, - ExploitabilityScore: 0, - ImpactScore: 0, - Vector: vulnerability.Vulnerability.Metadata.NVD.CVSSv2.Vectors, - } - } - - // find all URLs related to the vulnerability - links := []string{vulnerability.Vulnerability.Link} - if vulnerability.Vulnerability.Metadata.CVE != nil { - for _, cve := range vulnerability.Vulnerability.Metadata.CVE { - if cve.Link != "" { - links = append(links, cve.Link) - } - } - } - - // create vulnerability metadata entry (a single entry keyed off of the vulnerability ID) - metadata := grypeDB.VulnerabilityMetadata{ - ID: vulnerability.Vulnerability.Name, - RecordSource: recordSource, - Severity: vulnerability.Vulnerability.Severity, - Links: links, - Description: vulnerability.Vulnerability.Description, - CvssV2: cvssV2, - } - - return transformers.NewEntries(allVulns, metadata), nil -} - -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/v1/transformers/os/transform_test.go b/pkg/process/v1/transformers/os/transform_test.go deleted file mode 100644 index 1b3b7560..00000000 --- a/pkg/process/v1/transformers/os/transform_test.go +++ /dev/null @@ -1,489 +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/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v1" -) - -func TestUnmarshalVulnerabilitiesEntries(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) - - require.Len(t, entries, 3) -} - -func TestParseVulnerabilitiesEntry(t *testing.T) { - tests := []struct { - name string - numEntries int - fixture string - vulns []grypeDB.Vulnerability - metadata grypeDB.VulnerabilityMetadata - }{ - { - name: "Amazon", - numEntries: 1, - fixture: "test-fixtures/amzn.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "ALAS-2018-1106", - RecordSource: "vulnerabilities:amzn:2", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2018-14648"}, - PackageName: "389-ds-base", - Namespace: "amzn:2", - FixedInVersion: "1.3.8.4-15.amzn2.0.1", - }, - { - ID: "ALAS-2018-1106", - RecordSource: "vulnerabilities:amzn:2", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2018-14648"}, - PackageName: "389-ds-base-debuginfo", - Namespace: "amzn:2", - FixedInVersion: "1.3.8.4-15.amzn2.0.1", - }, - { - ID: "ALAS-2018-1106", - RecordSource: "vulnerabilities:amzn:2", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2018-14648"}, - PackageName: "389-ds-base-devel", - Namespace: "amzn:2", - FixedInVersion: "1.3.8.4-15.amzn2.0.1", - }, - { - ID: "ALAS-2018-1106", - RecordSource: "vulnerabilities:amzn:2", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2018-14648"}, - PackageName: "389-ds-base-libs", - Namespace: "amzn:2", - FixedInVersion: "1.3.8.4-15.amzn2.0.1", - }, - { - ID: "ALAS-2018-1106", - RecordSource: "vulnerabilities:amzn:2", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2018-14648"}, - PackageName: "389-ds-base-snmp", - Namespace: "amzn:2", - FixedInVersion: "1.3.8.4-15.amzn2.0.1", - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "ALAS-2018-1106", - RecordSource: "vulnerabilities:amzn:2", - Severity: "Medium", - Links: []string{"https://alas.aws.amazon.com/AL2/ALAS-2018-1106.html"}, - }, - }, - { - name: "Debian", - numEntries: 1, - fixture: "test-fixtures/debian-8.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2008-7220", - RecordSource: "vulnerabilities:debian:8", - PackageName: "asterisk", - VersionConstraint: "< 1:1.6.2.0~rc3-1", - VersionFormat: "dpkg", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "debian:8", - FixedInVersion: "1:1.6.2.0~rc3-1", - }, - { - ID: "CVE-2008-7220", - RecordSource: "vulnerabilities:debian:8", - PackageName: "auth2db", - VersionConstraint: "< 0.2.5-2+dfsg-1", - VersionFormat: "dpkg", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "debian:8", - FixedInVersion: "0.2.5-2+dfsg-1", - }, - { - ID: "CVE-2008-7220", - RecordSource: "vulnerabilities:debian:8", - PackageName: "exaile", - VersionConstraint: "< 0.2.14+debian-2.2", - VersionFormat: "dpkg", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "debian:8", - FixedInVersion: "0.2.14+debian-2.2", - }, - { - ID: "CVE-2008-7220", - RecordSource: "vulnerabilities:debian:8", - PackageName: "wordpress", - VersionConstraint: "", - VersionFormat: "dpkg", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "debian:8", - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2008-7220", - RecordSource: "vulnerabilities:debian:8", - Severity: "High", - Links: []string{"https://security-tracker.debian.org/tracker/CVE-2008-7220"}, - Description: "", - CvssV2: &grypeDB.Cvss{ - BaseScore: 7.5, - Vector: "AV:N/AC:L/Au:N/C:P/I:P/A:P", - }, - }, - }, - { - name: "RHEL", - numEntries: 1, - fixture: "test-fixtures/rhel-8.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2020-6819", - RecordSource: "vulnerabilities:rhel:8", - PackageName: "firefox", - VersionConstraint: "< 0:68.6.1-1.el8_1", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "rhel:8", - FixedInVersion: "0:68.6.1-1.el8_1", - }, - { - ID: "CVE-2020-6819", - RecordSource: "vulnerabilities:rhel:8", - PackageName: "thunderbird", - VersionConstraint: "< 0:68.7.0-1.el8_1", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "rhel:8", - FixedInVersion: "0:68.7.0-1.el8_1", - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2020-6819", - RecordSource: "vulnerabilities:rhel:8", - Severity: "Critical", - Links: []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.", - }, - }, - { - name: "RHEL with modularity", - numEntries: 1, - fixture: "test-fixtures/rhel-8-modules.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2020-14350", - RecordSource: "vulnerabilities:rhel:8", - PackageName: "postgresql", - VersionConstraint: "< 0:12.5-1.module+el8.3.0+9042+664538f4", - VersionFormat: "rpm", - ProxyVulnerabilities: []string{}, - Namespace: "rhel:8", - FixedInVersion: "0:12.5-1.module+el8.3.0+9042+664538f4", - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2020-14350", - RecordSource: "vulnerabilities:rhel:8", - Severity: "Medium", - Links: []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.", - }, - }, - { - name: "Alpine", - numEntries: 1, - fixture: "test-fixtures/alpine-3.9.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2018-19967", - RecordSource: "vulnerabilities:alpine:3.9", - PackageName: "xen", - VersionConstraint: "< 4.11.1-r0", - VersionFormat: "apk", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "alpine:3.9", - FixedInVersion: "4.11.1-r0", - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2018-19967", - RecordSource: "vulnerabilities:alpine:3.9", - Severity: "Medium", - Links: []string{"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-19967"}, - Description: "", - CvssV2: &grypeDB.Cvss{ - BaseScore: 4.9, - ExploitabilityScore: 0, - ImpactScore: 0, - Vector: "AV:L/AC:L/Au:N/C:N/I:N/A:C", - }, - }, - }, - { - name: "Oracle", - numEntries: 1, - fixture: "test-fixtures/ol-8.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "ELSA-2020-2550", - RecordSource: "vulnerabilities:ol:8", - PackageName: "libexif", - VersionConstraint: "< 0:0.6.21-17.el8_2", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2020-13112"}, - Namespace: "ol:8", - FixedInVersion: "0:0.6.21-17.el8_2", - }, - { - ID: "ELSA-2020-2550", - RecordSource: "vulnerabilities:ol:8", - PackageName: "libexif-devel", - VersionConstraint: "< 0:0.6.21-17.el8_2", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2020-13112"}, - Namespace: "ol:8", - FixedInVersion: "0:0.6.21-17.el8_2", - }, - { - ID: "ELSA-2020-2550", - RecordSource: "vulnerabilities:ol:8", - PackageName: "libexif-dummy", - VersionConstraint: "", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2020-13112"}, - Namespace: "ol:8", - FixedInVersion: "", - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "ELSA-2020-2550", - RecordSource: "vulnerabilities:ol:8", - Severity: "Medium", - Links: []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", - RecordSource: "vulnerabilities:ol:8", - PackageName: "postgresql", - VersionConstraint: "< 0:12.5-1.module+el8.3.0+9042+664538f4", - VersionFormat: "rpm", - ProxyVulnerabilities: []string{}, - Namespace: "ol:8", - FixedInVersion: "0:12.5-1.module+el8.3.0+9042+664538f4", - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2020-14350", - RecordSource: "vulnerabilities:ol:8", - Severity: "Medium", - Links: []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") - } - } - - 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", - RecordSource: "vulnerabilities:debian:8", - PackageName: "rsyslog", - VersionConstraint: "< 5.7.4-1", - VersionFormat: "dpkg", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "debian:8", - FixedInVersion: "5.7.4-1", - }, - { - ID: "CVE-2008-5618", - RecordSource: "vulnerabilities:debian:8", - PackageName: "rsyslog", - VersionConstraint: "< 3.18.6-1", - VersionFormat: "dpkg", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "debian:8", - FixedInVersion: "3.18.6-1", - }, - }, - }, - { - name: "Amazon", - numEntries: 3, - fixture: "test-fixtures/amazon-multiple-kernel-advisories.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "ALAS-2021-1704", - RecordSource: "vulnerabilities:amzn:2", - PackageName: "kernel-headers", - VersionConstraint: "< 4.14.246-187.474.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - ProxyVulnerabilities: []string{"CVE-2021-3653", "CVE-2021-3656", "CVE-2021-3732"}, - FixedInVersion: "4.14.246-187.474.amzn2", - }, - { - ID: "ALAS-2021-1704", - RecordSource: "vulnerabilities:amzn:2", - PackageName: "kernel", - VersionConstraint: "< 4.14.246-187.474.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - ProxyVulnerabilities: []string{"CVE-2021-3653", "CVE-2021-3656", "CVE-2021-3732"}, - FixedInVersion: "4.14.246-187.474.amzn2", - }, - { - ID: "ALASKERNEL-5.4-2022-007", - RecordSource: "vulnerabilities:amzn:2", - PackageName: "kernel-headers", - VersionConstraint: ">= 5.4, < 5.4.144-69.257.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - ProxyVulnerabilities: []string{"CVE-2021-3753", "CVE-2021-40490"}, - FixedInVersion: "5.4.144-69.257.amzn2", - }, - { - ID: "ALASKERNEL-5.4-2022-007", - RecordSource: "vulnerabilities:amzn:2", - PackageName: "kernel", - VersionConstraint: ">= 5.4, < 5.4.144-69.257.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - ProxyVulnerabilities: []string{"CVE-2021-3753", "CVE-2021-40490"}, - FixedInVersion: "5.4.144-69.257.amzn2", - }, - { - ID: "ALASKERNEL-5.10-2022-005", - RecordSource: "vulnerabilities:amzn:2", - PackageName: "kernel-headers", - VersionConstraint: ">= 5.10, < 5.10.62-55.141.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - ProxyVulnerabilities: []string{"CVE-2021-3753", "CVE-2021-40490"}, - FixedInVersion: "5.10.62-55.141.amzn2", - }, - { - ID: "ALASKERNEL-5.10-2022-005", - RecordSource: "vulnerabilities:amzn:2", - PackageName: "kernel", - VersionConstraint: ">= 5.10, < 5.10.62-55.141.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - ProxyVulnerabilities: []string{"CVE-2021-3753", "CVE-2021-40490"}, - FixedInVersion: "5.10.62-55.141.amzn2", - }, - }, - }, - } - - 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 { - assert.NoError(t, err) - 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") - } - } - } - - if diff := cmp.Diff(test.vulns, vulns); diff != "" { - t.Errorf("vulnerabilities do not match (-want +got):\n%s", diff) - } - }) - } - -} diff --git a/pkg/process/v1/writer.go b/pkg/process/v1/writer.go deleted file mode 100644 index 256f81fe..00000000 --- a/pkg/process/v1/writer.go +++ /dev/null @@ -1,131 +0,0 @@ -package v1 - -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/v1" - grypeDBStore "github.com/anchore/grype/grype/db/v1/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.Contains(metadata.RecordSource, 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, "record-source", metadata.RecordSource, "from", metadata.Severity, "to", newSeverity).Trace("overriding irrelevant severity with data from NVD record") - } - metadata.Severity = newSeverity -} diff --git a/pkg/process/v1/writer_test.go b/pkg/process/v1/writer_test.go deleted file mode 100644 index a77255f2..00000000 --- a/pkg/process/v1/writer_test.go +++ /dev/null @@ -1,126 +0,0 @@ -package v1 - -import ( - "errors" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/anchore/grype-db/pkg/data" - grypeDB "github.com/anchore/grype/grype/db/v1" -) - -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, - RecordSource: "nvdv2:cves", - }, - } -} - -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 - recordSource string - cveID string - reader grypeDB.VulnerabilityMetadataStoreReader - expected data.Severity - }{ - { - name: "missing severity set to Unknown", - initialSeverity: "", - recordSource: "test", - reader: &mockReader{}, - expected: data.SeverityUnknown, - }, - { - name: "non-cve records metadata missing severity set to Unknown", - cveID: "GHSA-1234-1234-1234", - initialSeverity: "", - recordSource: "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", - recordSource: "test", - reader: newMockReader("critical"), // should not be used - expected: data.SeverityHigh, - }, - { - name: "override empty severity from NVD", - initialSeverity: "", - recordSource: "test", - reader: newMockReader("low"), - expected: data.SeverityLow, - }, - { - name: "override unknown severity from NVD", - initialSeverity: "unknown", - recordSource: "test", - reader: newMockReader("low"), - expected: data.SeverityLow, - }, - { - name: "ignore record with severity already set", - initialSeverity: "Low", - recordSource: "test", - reader: newMockReader("critical"), // should not be used - expected: data.SeverityLow, - }, - { - name: "ignore nvd records", - initialSeverity: "Low", - recordSource: "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: "", - recordSource: "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, - RecordSource: tt.recordSource, - } - if tt.cveID != "" { - record.ID = tt.cveID - } - normalizeSeverity(record, tt.reader) - assert.Equal(t, string(tt.expected), record.Severity) - }) - } -} diff --git a/pkg/process/v2/processors.go b/pkg/process/v2/processors.go deleted file mode 100644 index 19eb1ead..00000000 --- a/pkg/process/v2/processors.go +++ /dev/null @@ -1,17 +0,0 @@ -package v2 - -import ( - "github.com/anchore/grype-db/pkg/data" - "github.com/anchore/grype-db/pkg/process/processors" - "github.com/anchore/grype-db/pkg/process/v2/transformers/github" - "github.com/anchore/grype-db/pkg/process/v2/transformers/nvd" - "github.com/anchore/grype-db/pkg/process/v2/transformers/os" -) - -func Processors() []data.Processor { - return []data.Processor{ - processors.NewGitHubProcessor(github.Transform), - processors.NewNVDProcessor(nvd.Transform), - processors.NewOSProcessor(os.Transform), - } -} diff --git a/pkg/process/v2/transformers/entry.go b/pkg/process/v2/transformers/entry.go deleted file mode 100644 index 6109add5..00000000 --- a/pkg/process/v2/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/v2" -) - -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/v2/transformers/github/test-fixtures/github-github-npm-0.json b/pkg/process/v2/transformers/github/test-fixtures/github-github-npm-0.json deleted file mode 100644 index b0a7d1e9..00000000 --- a/pkg/process/v2/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/v2/transformers/github/test-fixtures/github-github-python-0.json b/pkg/process/v2/transformers/github/test-fixtures/github-github-python-0.json deleted file mode 100644 index ad14aa60..00000000 --- a/pkg/process/v2/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/v2/transformers/github/test-fixtures/github-github-python-1.json b/pkg/process/v2/transformers/github/test-fixtures/github-github-python-1.json deleted file mode 100644 index bfa84922..00000000 --- a/pkg/process/v2/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/v2/transformers/github/test-fixtures/github-withdrawn.json b/pkg/process/v2/transformers/github/test-fixtures/github-withdrawn.json deleted file mode 100644 index 04995e38..00000000 --- a/pkg/process/v2/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/v2/transformers/github/test-fixtures/multiple-fixed-in-names.json b/pkg/process/v2/transformers/github/test-fixtures/multiple-fixed-in-names.json deleted file mode 100644 index ac1ef982..00000000 --- a/pkg/process/v2/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/v2/transformers/github/transform.go b/pkg/process/v2/transformers/github/transform.go deleted file mode 100644 index 5efac22a..00000000 --- a/pkg/process/v2/transformers/github/transform.go +++ /dev/null @@ -1,65 +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/v2/transformers" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v2" -) - -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 != nil { - return nil, nil - } - - recordSource := grypeDB.RecordSource(feed, vulnerability.Advisory.Namespace) - - // 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 _, advisory := range vulnerability.Advisory.FixedIn { - constraint := common.EnforceSemVerConstraint(advisory.Range) - - var versionFormat string - switch vulnerability.Advisory.Namespace { - case "github:python": - versionFormat = "python" - default: - versionFormat = "unknown" - } - - // create vulnerability entry - vuln := grypeDB.Vulnerability{ - ID: vulnerability.Advisory.GhsaID, - RecordSource: recordSource, - VersionConstraint: constraint, - VersionFormat: versionFormat, // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: vulnerability.Advisory.CVE, - PackageName: advisory.Name, - Namespace: advisory.Namespace, - FixedInVersion: common.CleanFixedInVersion(advisory.Identifier), - } - - allVulns = append(allVulns, vuln) - } - - // create vulnerability metadata entry (a single entry keyed off of the vulnerability ID) - metadata := grypeDB.VulnerabilityMetadata{ - ID: vulnerability.Advisory.GhsaID, - RecordSource: recordSource, - Severity: vulnerability.Advisory.Severity, - Links: []string{vulnerability.Advisory.URL}, - Description: vulnerability.Advisory.Summary, - } - - return transformers.NewEntries(allVulns, metadata), nil -} diff --git a/pkg/process/v2/transformers/github/transform_test.go b/pkg/process/v2/transformers/github/transform_test.go deleted file mode 100644 index d5ceed9e..00000000 --- a/pkg/process/v2/transformers/github/transform_test.go +++ /dev/null @@ -1,170 +0,0 @@ -package github - -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/v2" -) - -func TestUnmarshalGitHubEntries(t *testing.T) { - f, err := os.Open("test-fixtures/github-github-python-0.json") - require.NoError(t, err) - t.Cleanup(func() { - assert.NoError(t, f.Close()) - }) - - entries, err := unmarshal.GitHubAdvisoryEntries(f) - require.NoError(t, err) - - require.Len(t, entries, 2) -} - -func TestParseGitHubEntry(t *testing.T) { - expectedVulns := []grypeDB.Vulnerability{ - { - ID: "GHSA-p5wr-vp8g-q5p4", - RecordSource: "github:python", - VersionConstraint: ">=4.0,<4.3.12", - VersionFormat: "python", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2017-5524"}, - PackageName: "Plone", - Namespace: "github:python", - FixedInVersion: "4.3.12", - }, - { - ID: "GHSA-p5wr-vp8g-q5p4", - RecordSource: "github:python", - VersionConstraint: ">=5.1a1,<5.1b1", - VersionFormat: "python", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2017-5524"}, - PackageName: "Plone", - Namespace: "github:python", - FixedInVersion: "5.1b1", - }, - { - ID: "GHSA-p5wr-vp8g-q5p4", - RecordSource: "github:python", - VersionConstraint: ">=5.0rc1,<5.0.7", - VersionFormat: "python", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2017-5524"}, - PackageName: "Plone", - Namespace: "github:python", - FixedInVersion: "5.0.7", - }, - } - - expectedMetadata := grypeDB.VulnerabilityMetadata{ - ID: "GHSA-p5wr-vp8g-q5p4", - RecordSource: "github:python", - Severity: "Medium", - Links: []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) - 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, 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)) - - assert.ElementsMatch(t, expectedVulns, vulns) - -} - -func TestDefaultVersionFormatNpmGitHubEntry(t *testing.T) { - expectedVulns := []grypeDB.Vulnerability{ - { - ID: "GHSA-vc9j-fhvv-8vrf", - RecordSource: "github:npm", - VersionConstraint: "<=0.2.0-prerelease.20200709173451", - VersionFormat: "unknown", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2020-14000"}, - PackageName: "scratch-vm", - Namespace: "github:npm", - FixedInVersion: "0.2.0-prerelease.20200714185213", - }, - } - - expectedMetadata := grypeDB.VulnerabilityMetadata{ - ID: "GHSA-vc9j-fhvv-8vrf", - RecordSource: "github:npm", - Severity: "High", - Links: []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) - 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, 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)) - - assert.ElementsMatch(t, expectedVulns, vulns) -} - -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/v2/transformers/nvd/test-fixtures/compound-pkg.json b/pkg/process/v2/transformers/nvd/test-fixtures/compound-pkg.json deleted file mode 100644 index 8e658dcd..00000000 --- a/pkg/process/v2/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/v2/transformers/nvd/test-fixtures/invalid_cpe.json b/pkg/process/v2/transformers/nvd/test-fixtures/invalid_cpe.json deleted file mode 100644 index eac2ebd4..00000000 --- a/pkg/process/v2/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/v2/transformers/nvd/test-fixtures/single-package-multi-distro.json b/pkg/process/v2/transformers/nvd/test-fixtures/single-package-multi-distro.json deleted file mode 100644 index ed108475..00000000 --- a/pkg/process/v2/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/v2/transformers/nvd/test-fixtures/unmarshal-test.json b/pkg/process/v2/transformers/nvd/test-fixtures/unmarshal-test.json deleted file mode 100644 index 2dc698fa..00000000 --- a/pkg/process/v2/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/v2/transformers/nvd/test-fixtures/version-range.json b/pkg/process/v2/transformers/nvd/test-fixtures/version-range.json deleted file mode 100644 index 3df5b86d..00000000 --- a/pkg/process/v2/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/v2/transformers/nvd/transform.go b/pkg/process/v2/transformers/nvd/transform.go deleted file mode 100644 index a50e13af..00000000 --- a/pkg/process/v2/transformers/nvd/transform.go +++ /dev/null @@ -1,111 +0,0 @@ -package nvd - -import ( - "strings" - - "github.com/anchore/grype-db/internal" - "github.com/anchore/grype-db/pkg/data" - "github.com/anchore/grype-db/pkg/process/v2/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/v2" -) - -const ( - // TODO: tech debt from a previous design - feed = "nvdv2" - group = "nvdv2:cves" -) - -func Transform(vulnerability unmarshal.NVDVulnerability) ([]data.Entry, error) { - var allVulns []grypeDB.Vulnerability - - recordSource := grypeDB.RecordSource(feed, group) - - 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 - for _, p := range uniquePkgs.All() { - matches := uniquePkgs.Matches(p) - cpes := internal.NewStringSet() - for _, m := range matches { - cpes.Add(m.Criteria) - } - - // create vulnerability entry - vuln := grypeDB.Vulnerability{ - ID: vulnerability.ID, - RecordSource: recordSource, - VersionConstraint: buildConstraints(matches), - VersionFormat: "unknown", // TODO: derive this from the target software - PackageName: p.Product, - Namespace: "nvd", // should the vendor be here? or in other metadata? - ProxyVulnerabilities: []string{}, - CPEs: cpes.ToSlice(), - } - - allVulns = append(allVulns, vuln) - } - - // If all the CPEs are invalid and no vulnerabilities were generated then there is no point - // in creating metadata, so just return - if len(allVulns) == 0 { - return nil, nil - } - - // create vulnerability metadata entry (a single entry keyed off of the vulnerability ID) - allCVSS := vulnerability.CVSS() - - metadata := grypeDB.VulnerabilityMetadata{ - ID: vulnerability.ID, - RecordSource: recordSource, - Severity: nvd.CvssSummaries(allCVSS).Sorted().Severity(), - Links: links, - Description: vulnerability.Description(), - } - - for _, c := range allCVSS { - if strings.HasPrefix(c.Version, "2.") { - newCvss := &grypeDB.Cvss{ - BaseScore: c.BaseScore, - Vector: c.Vector, - } - if c.ExploitabilityScore != nil { - newCvss.ExploitabilityScore = *c.ExploitabilityScore - } - if c.ImpactScore != nil { - newCvss.ImpactScore = *c.ImpactScore - } - metadata.CvssV2 = newCvss - break - } - } - - for _, c := range allCVSS { - if strings.HasPrefix(c.Version, "3.") { - newCvss := &grypeDB.Cvss{ - BaseScore: c.BaseScore, - Vector: c.Vector, - } - if c.ExploitabilityScore != nil { - newCvss.ExploitabilityScore = *c.ExploitabilityScore - } - if c.ImpactScore != nil { - newCvss.ImpactScore = *c.ImpactScore - } - metadata.CvssV3 = newCvss - break - } - } - - return transformers.NewEntries(allVulns, metadata), nil -} diff --git a/pkg/process/v2/transformers/nvd/transform_test.go b/pkg/process/v2/transformers/nvd/transform_test.go deleted file mode 100644 index b508d0ac..00000000 --- a/pkg/process/v2/transformers/nvd/transform_test.go +++ /dev/null @@ -1,190 +0,0 @@ -package nvd - -import ( - "os" - "testing" - - "github.com/go-test/deep" - "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/v2" -) - -func TestUnmarshalVulnerabilitiesEntries(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) - - require.Len(t, entries, 1) -} - -func TestParseVulnerabilitiesAllEntries(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", - RecordSource: "nvdv2:cves", - PackageName: "oncommand_unified_manager", - VersionConstraint: ">= 7.2, <= 7.3", - VersionFormat: "unknown", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "nvd", - CPEs: []string{"cpe:2.3:a:netapp:oncommand_unified_manager:*:*:*:*:*:*:*:*"}, - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2018-5487", - RecordSource: "nvdv2:cves", - Severity: "Critical", - Links: []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.", - CvssV2: &grypeDB.Cvss{ - BaseScore: 7.5, - ExploitabilityScore: 10, - ImpactScore: 6.4, - Vector: "AV:N/AC:L/Au:N/C:P/I:P/A:P", - }, - CvssV3: &grypeDB.Cvss{ - BaseScore: 9.8, - ExploitabilityScore: 3.9, - ImpactScore: 5.9, - Vector: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", - }, - }, - }, - { - name: "App+OS", - numEntries: 1, - fixture: "test-fixtures/single-package-multi-distro.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2018-1000222", - RecordSource: "nvdv2:cves", - PackageName: "libgd", - VersionConstraint: "= 2.2.5", - VersionFormat: "unknown", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "nvd", - CPEs: []string{"cpe:2.3:a:libgd:libgd:2.2.5:*:*:*:*:*:*:*"}, - }, - // 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", - RecordSource: "nvdv2:cves", - Severity: "High", - Links: []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.", - CvssV2: &grypeDB.Cvss{ - BaseScore: 6.8, - ExploitabilityScore: 8.6, - ImpactScore: 6.4, - Vector: "AV:N/AC:M/Au:N/C:P/I:P/A:P", - }, - CvssV3: &grypeDB.Cvss{ - BaseScore: 8.8, - ExploitabilityScore: 2.8, - ImpactScore: 5.9, - Vector: "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H", - }, - }, - }, - { - name: "AppCompoundVersionRange", - numEntries: 1, - fixture: "test-fixtures/compound-pkg.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2018-10189", - RecordSource: "nvdv2:cves", - PackageName: "mautic", - VersionConstraint: ">= 1.0.0, <= 1.4.1 || >= 2.0.0, < 2.13.0", - VersionFormat: "unknown", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "nvd", - CPEs: []string{"cpe:2.3:a:mautic:mautic:*:*:*:*:*:*:*:*"}, // note: entry was dedupicated - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2018-10189", - RecordSource: "nvdv2:cves", - Severity: "High", - Links: []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.", - CvssV2: &grypeDB.Cvss{ - BaseScore: 5, - ExploitabilityScore: 10, - ImpactScore: 2.9, - Vector: "AV:N/AC:L/Au:N/C:P/I:N/A:N", - }, - CvssV3: &grypeDB.Cvss{ - BaseScore: 7.5, - ExploitabilityScore: 3.9, - ImpactScore: 3.6, - Vector: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", - }, - }, - }, - { - name: "InvalidCPE", - numEntries: 1, - fixture: "test-fixtures/invalid_cpe.json", - vulns: []grypeDB.Vulnerability{}, - metadata: grypeDB.VulnerabilityMetadata{}, - }, - } - - 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) - assert.NoError(t, err) - - var vulns []grypeDB.Vulnerability - for _, entry := range entries { - dataEntries, err := Transform(entry.Cve) - assert.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") - } - } - - } - - assert.ElementsMatch(t, test.vulns, vulns) - }) - } -} diff --git a/pkg/process/v2/transformers/nvd/unique_pkg.go b/pkg/process/v2/transformers/nvd/unique_pkg.go deleted file mode 100644 index 34621368..00000000 --- a/pkg/process/v2/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/v2/transformers/nvd/unique_pkg_test.go b/pkg/process/v2/transformers/nvd/unique_pkg_test.go deleted file mode 100644 index beb050fc..00000000 --- a/pkg/process/v2/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: %q", test.expected) - t.Errorf("Got : %q", actual) - t.Errorf("Diff : %q", dmp.DiffPrettyText(diffs)) - } - }) - } - -} diff --git a/pkg/process/v2/transformers/nvd/unique_pkg_tracker.go b/pkg/process/v2/transformers/nvd/unique_pkg_tracker.go deleted file mode 100644 index 2b7e405d..00000000 --- a/pkg/process/v2/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/v2/transformers/os/test-fixtures/alpine-3.9.json b/pkg/process/v2/transformers/os/test-fixtures/alpine-3.9.json deleted file mode 100644 index b9d84395..00000000 --- a/pkg/process/v2/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/v2/transformers/os/test-fixtures/amazon-multiple-kernel-advisories.json b/pkg/process/v2/transformers/os/test-fixtures/amazon-multiple-kernel-advisories.json deleted file mode 100644 index 82f2b45b..00000000 --- a/pkg/process/v2/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/v2/transformers/os/test-fixtures/amzn.json b/pkg/process/v2/transformers/os/test-fixtures/amzn.json deleted file mode 100644 index a862c32e..00000000 --- a/pkg/process/v2/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/v2/transformers/os/test-fixtures/debian-8-multiple-entries-for-same-package.json b/pkg/process/v2/transformers/os/test-fixtures/debian-8-multiple-entries-for-same-package.json deleted file mode 100644 index 5025b56e..00000000 --- a/pkg/process/v2/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/v2/transformers/os/test-fixtures/debian-8.json b/pkg/process/v2/transformers/os/test-fixtures/debian-8.json deleted file mode 100644 index a758f13c..00000000 --- a/pkg/process/v2/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/v2/transformers/os/test-fixtures/ol-8-modules.json b/pkg/process/v2/transformers/os/test-fixtures/ol-8-modules.json deleted file mode 100644 index f1d7372b..00000000 --- a/pkg/process/v2/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/v2/transformers/os/test-fixtures/ol-8.json b/pkg/process/v2/transformers/os/test-fixtures/ol-8.json deleted file mode 100644 index 09439ece..00000000 --- a/pkg/process/v2/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/v2/transformers/os/test-fixtures/rhel-8-modules.json b/pkg/process/v2/transformers/os/test-fixtures/rhel-8-modules.json deleted file mode 100644 index c0400ad5..00000000 --- a/pkg/process/v2/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/v2/transformers/os/test-fixtures/rhel-8.json b/pkg/process/v2/transformers/os/test-fixtures/rhel-8.json deleted file mode 100644 index 2779708c..00000000 --- a/pkg/process/v2/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/v2/transformers/os/test-fixtures/unmarshal-test.json b/pkg/process/v2/transformers/os/test-fixtures/unmarshal-test.json deleted file mode 100644 index edc6d25b..00000000 --- a/pkg/process/v2/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/v2/transformers/os/transform.go b/pkg/process/v2/transformers/os/transform.go deleted file mode 100644 index 436b7c17..00000000 --- a/pkg/process/v2/transformers/os/transform.go +++ /dev/null @@ -1,118 +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/v2/transformers" - "github.com/anchore/grype-db/pkg/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v2" -) - -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) - 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 _, advisory := range vulnerability.Vulnerability.FixedIn { - // create vulnerability entry - vuln := grypeDB.Vulnerability{ - ID: vulnerability.Vulnerability.Name, - RecordSource: recordSource, - VersionConstraint: enforceConstraint(advisory.Version, advisory.VersionFormat, vulnerability.Vulnerability.Name), - VersionFormat: advisory.VersionFormat, - PackageName: advisory.Name, - Namespace: advisory.NamespaceName, - ProxyVulnerabilities: []string{}, - FixedInVersion: common.CleanFixedInVersion(advisory.Version), - } - - // associate related vulnerabilities - // 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 vulnerability.Vulnerability.Metadata.CVE { - vuln.ProxyVulnerabilities = append(vuln.ProxyVulnerabilities, ref.Name) - } - - allVulns = append(allVulns, vuln) - } - - var cvssV2 *grypeDB.Cvss - if vulnerability.Vulnerability.Metadata.NVD.CVSSv2.Vectors != "" { - cvssV2 = &grypeDB.Cvss{ - BaseScore: vulnerability.Vulnerability.Metadata.NVD.CVSSv2.Score, - ExploitabilityScore: 0, - ImpactScore: 0, - Vector: vulnerability.Vulnerability.Metadata.NVD.CVSSv2.Vectors, - } - } - - // find all URLs related to the vulnerability - links := []string{vulnerability.Vulnerability.Link} - if vulnerability.Vulnerability.Metadata.CVE != nil { - for _, cve := range vulnerability.Vulnerability.Metadata.CVE { - if cve.Link != "" { - links = append(links, cve.Link) - } - } - } - - // create vulnerability metadata entry (a single entry keyed off of the vulnerability ID) - metadata := grypeDB.VulnerabilityMetadata{ - ID: vulnerability.Vulnerability.Name, - RecordSource: recordSource, - Severity: vulnerability.Vulnerability.Severity, - Links: links, - Description: vulnerability.Vulnerability.Description, - CvssV2: cvssV2, - } - - return transformers.NewEntries(allVulns, metadata), nil -} - -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/v2/transformers/os/transform_test.go b/pkg/process/v2/transformers/os/transform_test.go deleted file mode 100644 index b699fb40..00000000 --- a/pkg/process/v2/transformers/os/transform_test.go +++ /dev/null @@ -1,500 +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/provider/unmarshal" - grypeDB "github.com/anchore/grype/grype/db/v2" -) - -func TestUnmarshalVulnerabilitiesEntries(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) - - require.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", - RecordSource: "vulnerabilities:amzn:2", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2018-14648"}, - PackageName: "389-ds-base", - Namespace: "amzn:2", - FixedInVersion: "1.3.8.4-15.amzn2.0.1", - }, - { - ID: "ALAS-2018-1106", - RecordSource: "vulnerabilities:amzn:2", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2018-14648"}, - PackageName: "389-ds-base-debuginfo", - Namespace: "amzn:2", - FixedInVersion: "1.3.8.4-15.amzn2.0.1", - }, - { - ID: "ALAS-2018-1106", - RecordSource: "vulnerabilities:amzn:2", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2018-14648"}, - PackageName: "389-ds-base-devel", - Namespace: "amzn:2", - FixedInVersion: "1.3.8.4-15.amzn2.0.1", - }, - { - ID: "ALAS-2018-1106", - RecordSource: "vulnerabilities:amzn:2", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2018-14648"}, - PackageName: "389-ds-base-libs", - Namespace: "amzn:2", - FixedInVersion: "1.3.8.4-15.amzn2.0.1", - }, - { - ID: "ALAS-2018-1106", - RecordSource: "vulnerabilities:amzn:2", - VersionConstraint: "< 1.3.8.4-15.amzn2.0.1", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2018-14648"}, - PackageName: "389-ds-base-snmp", - Namespace: "amzn:2", - FixedInVersion: "1.3.8.4-15.amzn2.0.1", - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "ALAS-2018-1106", - RecordSource: "vulnerabilities:amzn:2", - Severity: "Medium", - Links: []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", - RecordSource: "vulnerabilities:debian:8", - PackageName: "asterisk", - VersionConstraint: "< 1:1.6.2.0~rc3-1", - VersionFormat: "dpkg", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "debian:8", - FixedInVersion: "1:1.6.2.0~rc3-1", - }, - { - ID: "CVE-2008-7220", - RecordSource: "vulnerabilities:debian:8", - PackageName: "auth2db", - VersionConstraint: "< 0.2.5-2+dfsg-1", - VersionFormat: "dpkg", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "debian:8", - FixedInVersion: "0.2.5-2+dfsg-1", - }, - { - ID: "CVE-2008-7220", - RecordSource: "vulnerabilities:debian:8", - PackageName: "exaile", - VersionConstraint: "< 0.2.14+debian-2.2", - VersionFormat: "dpkg", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "debian:8", - FixedInVersion: "0.2.14+debian-2.2", - }, - { - ID: "CVE-2008-7220", - RecordSource: "vulnerabilities:debian:8", - PackageName: "wordpress", - VersionConstraint: "", - VersionFormat: "dpkg", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "debian:8", - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2008-7220", - RecordSource: "vulnerabilities:debian:8", - Severity: "High", - Links: []string{"https://security-tracker.debian.org/tracker/CVE-2008-7220"}, - Description: "", - CvssV2: &grypeDB.Cvss{ - BaseScore: 7.5, - Vector: "AV:N/AC:L/Au:N/C:P/I:P/A:P", - }, - }, - }, - { - name: "RHEL", - numEntries: 1, - fixture: "test-fixtures/rhel-8.json", - feed: "vulnerabilities", - group: "rhel:8", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2020-6819", - RecordSource: "vulnerabilities:rhel:8", - PackageName: "firefox", - VersionConstraint: "< 0:68.6.1-1.el8_1", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "rhel:8", - FixedInVersion: "0:68.6.1-1.el8_1", - }, - { - ID: "CVE-2020-6819", - RecordSource: "vulnerabilities:rhel:8", - PackageName: "thunderbird", - VersionConstraint: "< 0:68.7.0-1.el8_1", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "rhel:8", - FixedInVersion: "0:68.7.0-1.el8_1", - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2020-6819", - RecordSource: "vulnerabilities:rhel:8", - Severity: "Critical", - Links: []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.", - }, - }, - { - 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", - RecordSource: "vulnerabilities:rhel:8", - PackageName: "postgresql", - VersionConstraint: "< 0:12.5-1.module+el8.3.0+9042+664538f4", - VersionFormat: "rpm", - ProxyVulnerabilities: []string{}, - Namespace: "rhel:8", - FixedInVersion: "0:12.5-1.module+el8.3.0+9042+664538f4", - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2020-14350", - RecordSource: "vulnerabilities:rhel:8", - Severity: "Medium", - Links: []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.", - }, - }, - { - name: "Alpine", - numEntries: 1, - fixture: "test-fixtures/alpine-3.9.json", - feed: "vulnerabilities", - group: "alpine:3.9", - vulns: []grypeDB.Vulnerability{ - { - ID: "CVE-2018-19967", - RecordSource: "vulnerabilities:alpine:3.9", - PackageName: "xen", - VersionConstraint: "< 4.11.1-r0", - VersionFormat: "apk", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "alpine:3.9", - FixedInVersion: "4.11.1-r0", - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2018-19967", - RecordSource: "vulnerabilities:alpine:3.9", - Severity: "Medium", - Links: []string{"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-19967"}, - Description: "", - CvssV2: &grypeDB.Cvss{ - BaseScore: 4.9, - ExploitabilityScore: 0, - ImpactScore: 0, - Vector: "AV:L/AC:L/Au:N/C:N/I:N/A:C", - }, - }, - }, - { - name: "Oracle", - numEntries: 1, - fixture: "test-fixtures/ol-8.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "ELSA-2020-2550", - RecordSource: "vulnerabilities:ol:8", - PackageName: "libexif", - VersionConstraint: "< 0:0.6.21-17.el8_2", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2020-13112"}, - Namespace: "ol:8", - FixedInVersion: "0:0.6.21-17.el8_2", - }, - { - ID: "ELSA-2020-2550", - RecordSource: "vulnerabilities:ol:8", - PackageName: "libexif-devel", - VersionConstraint: "< 0:0.6.21-17.el8_2", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2020-13112"}, - Namespace: "ol:8", - FixedInVersion: "0:0.6.21-17.el8_2", - }, - { - ID: "ELSA-2020-2550", - RecordSource: "vulnerabilities:ol:8", - PackageName: "libexif-dummy", - VersionConstraint: "", - VersionFormat: "rpm", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{"CVE-2020-13112"}, - Namespace: "ol:8", - FixedInVersion: "", - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "ELSA-2020-2550", - RecordSource: "vulnerabilities:ol:8", - Severity: "Medium", - Links: []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", - RecordSource: "vulnerabilities:ol:8", - PackageName: "postgresql", - VersionConstraint: "< 0:12.5-1.module+el8.3.0+9042+664538f4", - VersionFormat: "rpm", - ProxyVulnerabilities: []string{}, - Namespace: "ol:8", - FixedInVersion: "0:12.5-1.module+el8.3.0+9042+664538f4", - }, - }, - metadata: grypeDB.VulnerabilityMetadata{ - ID: "CVE-2020-14350", - RecordSource: "vulnerabilities:ol:8", - Severity: "Medium", - Links: []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") - } - } - - 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", - RecordSource: "vulnerabilities:debian:8", - PackageName: "rsyslog", - VersionConstraint: "< 5.7.4-1", - VersionFormat: "dpkg", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "debian:8", - FixedInVersion: "5.7.4-1", - }, - { - ID: "CVE-2008-5618", - RecordSource: "vulnerabilities:debian:8", - PackageName: "rsyslog", - VersionConstraint: "< 3.18.6-1", - VersionFormat: "dpkg", // TODO: this should reference a format, yes? (not a string) - ProxyVulnerabilities: []string{}, - Namespace: "debian:8", - FixedInVersion: "3.18.6-1", - }, - }, - }, - { - name: "Amazon", - numEntries: 3, - fixture: "test-fixtures/amazon-multiple-kernel-advisories.json", - vulns: []grypeDB.Vulnerability{ - { - ID: "ALAS-2021-1704", - RecordSource: "vulnerabilities:amzn:2", - PackageName: "kernel-headers", - VersionConstraint: "< 4.14.246-187.474.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - ProxyVulnerabilities: []string{"CVE-2021-3653", "CVE-2021-3656", "CVE-2021-3732"}, - FixedInVersion: "4.14.246-187.474.amzn2", - }, - { - ID: "ALAS-2021-1704", - RecordSource: "vulnerabilities:amzn:2", - PackageName: "kernel", - VersionConstraint: "< 4.14.246-187.474.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - ProxyVulnerabilities: []string{"CVE-2021-3653", "CVE-2021-3656", "CVE-2021-3732"}, - FixedInVersion: "4.14.246-187.474.amzn2", - }, - { - ID: "ALASKERNEL-5.4-2022-007", - RecordSource: "vulnerabilities:amzn:2", - PackageName: "kernel-headers", - VersionConstraint: ">= 5.4, < 5.4.144-69.257.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - ProxyVulnerabilities: []string{"CVE-2021-3753", "CVE-2021-40490"}, - FixedInVersion: "5.4.144-69.257.amzn2", - }, - { - ID: "ALASKERNEL-5.4-2022-007", - RecordSource: "vulnerabilities:amzn:2", - PackageName: "kernel", - VersionConstraint: ">= 5.4, < 5.4.144-69.257.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - ProxyVulnerabilities: []string{"CVE-2021-3753", "CVE-2021-40490"}, - FixedInVersion: "5.4.144-69.257.amzn2", - }, - { - ID: "ALASKERNEL-5.10-2022-005", - RecordSource: "vulnerabilities:amzn:2", - PackageName: "kernel-headers", - VersionConstraint: ">= 5.10, < 5.10.62-55.141.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - ProxyVulnerabilities: []string{"CVE-2021-3753", "CVE-2021-40490"}, - FixedInVersion: "5.10.62-55.141.amzn2", - }, - { - ID: "ALASKERNEL-5.10-2022-005", - RecordSource: "vulnerabilities:amzn:2", - PackageName: "kernel", - VersionConstraint: ">= 5.10, < 5.10.62-55.141.amzn2", - VersionFormat: "rpm", - Namespace: "amzn:2", - ProxyVulnerabilities: []string{"CVE-2021-3753", "CVE-2021-40490"}, - FixedInVersion: "5.10.62-55.141.amzn2", - }, - }, - }, - } - - 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 { - assert.NoError(t, err) - 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") - } - } - } - - if diff := cmp.Diff(test.vulns, vulns); diff != "" { - t.Errorf("vulnerabilities do not match (-want +got):\n%s", diff) - } - }) - } - -} diff --git a/pkg/process/v2/writer.go b/pkg/process/v2/writer.go deleted file mode 100644 index a6dbd608..00000000 --- a/pkg/process/v2/writer.go +++ /dev/null @@ -1,131 +0,0 @@ -package v2 - -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/v2" - grypeDBStore "github.com/anchore/grype/grype/db/v2/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.Contains(metadata.RecordSource, 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, "record-source", metadata.RecordSource, "from", metadata.Severity, "to", newSeverity).Trace("overriding irrelevant severity with data from NVD record") - } - metadata.Severity = newSeverity -} diff --git a/pkg/process/v2/writer_test.go b/pkg/process/v2/writer_test.go deleted file mode 100644 index 840fc0ff..00000000 --- a/pkg/process/v2/writer_test.go +++ /dev/null @@ -1,126 +0,0 @@ -package v2 - -import ( - "errors" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/anchore/grype-db/pkg/data" - grypeDB "github.com/anchore/grype/grype/db/v2" -) - -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, - RecordSource: "nvdv2:cves", - }, - } -} - -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 - recordSource string - cveID string - reader grypeDB.VulnerabilityMetadataStoreReader - expected data.Severity - }{ - { - name: "missing severity set to Unknown", - initialSeverity: "", - recordSource: "test", - reader: &mockReader{}, - expected: data.SeverityUnknown, - }, - { - name: "non-cve records metadata missing severity set to Unknown", - cveID: "GHSA-1234-1234-1234", - initialSeverity: "", - recordSource: "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", - recordSource: "test", - reader: newMockReader("critical"), // should not be used - expected: data.SeverityHigh, - }, - { - name: "override empty severity from NVD", - initialSeverity: "", - recordSource: "test", - reader: newMockReader("low"), - expected: data.SeverityLow, - }, - { - name: "override unknown severity from NVD", - initialSeverity: "unknown", - recordSource: "test", - reader: newMockReader("low"), - expected: data.SeverityLow, - }, - { - name: "ignore record with severity already set", - initialSeverity: "Low", - recordSource: "test", - reader: newMockReader("critical"), // should not be used - expected: data.SeverityLow, - }, - { - name: "ignore nvd records", - initialSeverity: "Low", - recordSource: "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: "", - recordSource: "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, - RecordSource: tt.recordSource, - } - if tt.cveID != "" { - record.ID = tt.cveID - } - normalizeSeverity(record, tt.reader) - assert.Equal(t, string(tt.expected), record.Severity) - }) - } -}