From 15dd67c7f25f6baadf8322ecb948bd8b70f67e9a Mon Sep 17 00:00:00 2001 From: Minsi Yang Date: Sun, 23 Apr 2023 16:32:55 +0100 Subject: [PATCH] fix: align container sarif output --- .github/CODEOWNERS | 16 +-- src/lib/formatters/get-sarif-result.ts | 44 ++++++++ .../formatters/open-source-sarif-output.ts | 48 +-------- src/lib/formatters/sarif-output.ts | 43 ++------ .../docker/sarif-container-result.json | 31 +++--- .../__snapshots__/sarif-output.spec.ts.snap | 89 ++++++++++++++- .../unit/lib/formatters/sarif-output.spec.ts | 102 +++++++++++++----- 7 files changed, 247 insertions(+), 126 deletions(-) create mode 100644 src/lib/formatters/get-sarif-result.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 30891f9022..8bc7da996b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -21,19 +21,21 @@ src/cli/commands/describe.ts @snyk/cloud-context src/cli/commands/update-exclude-policy.ts @snyk/cloud-dev-ex src/cli/commands/apps @snyk/moose src/lib/apps @snyk/moose -src/lib/container @snyk/mycelium +src/lib/container @snyk/lumos src/lib/plugins @snyk/snyk-open-source test/fixtures/sast/ @snyk/zenith src/lib/plugins/sast/ @snyk/zenith test/jest/unit/snyk-code/ @snyk/zenith src/lib/formatters/iac-output/ @snyk/cloud-dev-ex +src/lib/formatters/sarif-output.ts @snyk/container +src/lib/formatters/get-sarif-result.ts @snyk/container @snyk/hammerhead @snyk/snyk-open-source src/lib/iac/ @snyk/group-infrastructure-as-code src/lib/iac/test/ @snyk/cloud-dev-ex src/lib/snyk-test/iac-test-result.ts @snyk/cloud-dev-ex -test/fixtures/basic-apk/ @snyk/mycelium -test/fixtures/container-app-vulns/ @snyk/mycelium -test/fixtures/container-projects/ @snyk/mycelium @snyk/potion -test/fixtures/docker/ @snyk/mycelium @snyk/potion +test/fixtures/basic-apk/ @snyk/lumos +test/fixtures/container-app-vulns/ @snyk/lumos +test/fixtures/container-projects/ @snyk/lumos +test/fixtures/docker/ @snyk/lumos test/fixtures/iac/ @snyk/cloud-dev-ex test/fixtures/iac/drift @snyk/cloud-context test/fixtures/iac/capture @snyk/cloud-context @@ -43,7 +45,7 @@ test/smoke/spec/snyk_basic_spec.sh @snyk/hammerhead test/smoke/.iac-data/ @snyk/cloud-dev-ex test/jest/unit/lib/endpoint-config-test.spec.ts @snyk/nebula test/jest/unit/lib/formatters/iac-output/ @snyk/cloud-dev-ex -test/jest/unit/lib/formatters/test/format-test-results.spec.ts @snyk/hammerhead @snyk/snyk-open-source @snyk/mycelium +test/jest/unit/lib/formatters/test/format-test-results.spec.ts @snyk/hammerhead @snyk/snyk-open-source @snyk/lumos test/jest/unit/iac/ @snyk/cloud-dev-ex test/jest/unit/cli/commands/test/iac @snyk/cloud-dev-ex test/jest/unit/lib/iac/drift/ @snyk/cloud-context @@ -72,7 +74,7 @@ src/cli/commands/log4shell-hashes.ts @snyk/tundra src/cli/commands/log4shell.ts @snyk/tundra test/fixtures/unmanaged-log4j-fixture @snyk/tundra test/jest/acceptance/snyk-log4shell/log4shell-detection.spec.ts @snyk/tundra -test/jest/acceptance/snyk-test/app-vuln-container-project.spec.ts @snyk/mycelium +test/jest/acceptance/snyk-test/app-vuln-container-project.spec.ts @snyk/lumos /.github @snyk/hammerhead /.github/workflows/iac-smoke-tests.yml @snyk/cloud-dev-ex /.github/workflows/iac-smoke-tests-pulls.yml @snyk/cloud-dev-ex diff --git a/src/lib/formatters/get-sarif-result.ts b/src/lib/formatters/get-sarif-result.ts new file mode 100644 index 0000000000..0bc56ec849 --- /dev/null +++ b/src/lib/formatters/get-sarif-result.ts @@ -0,0 +1,44 @@ +import * as sarif from 'sarif'; +import * as groupBy from 'lodash.groupby'; +import * as map from 'lodash.map'; + +import { SEVERITY, AnnotatedIssue } from '../snyk-test/legacy'; + +export function getResults(testResult): sarif.Result[] { + const groupedVulnerabilities = groupBy(testResult.vulnerabilities, 'id'); + return map( + groupedVulnerabilities, + ([vuln]): sarif.Result => ({ + ruleId: vuln.id, + level: getLevel(vuln), + message: { + text: `This file introduces a vulnerable ${vuln.packageName} package with a ${vuln.severity} severity vulnerability.`, + }, + locations: [ + { + physicalLocation: { + artifactLocation: { + uri: testResult.displayTargetFile, + }, + region: { + startLine: vuln.lineNumber || 1, + }, + }, + }, + ], + }), + ); +} + +export function getLevel(vuln: AnnotatedIssue) { + switch (vuln.severity) { + case SEVERITY.CRITICAL: + case SEVERITY.HIGH: + return 'error'; + case SEVERITY.MEDIUM: + return 'warning'; + case SEVERITY.LOW: + default: + return 'note'; + } +} diff --git a/src/lib/formatters/open-source-sarif-output.ts b/src/lib/formatters/open-source-sarif-output.ts index 843ba4217f..49f2ec232c 100644 --- a/src/lib/formatters/open-source-sarif-output.ts +++ b/src/lib/formatters/open-source-sarif-output.ts @@ -1,9 +1,10 @@ import * as sarif from 'sarif'; -const upperFirst = require('lodash.upperfirst'); -const groupBy = require('lodash.groupby'); -const map = require('lodash.map'); +import * as upperFirst from 'lodash.upperfirst'; +import * as groupBy from 'lodash.groupby'; +import * as map from 'lodash.map'; -import { TestResult, SEVERITY, AnnotatedIssue } from '../snyk-test/legacy'; +import { TestResult, AnnotatedIssue } from '../snyk-test/legacy'; +import { getResults } from './get-sarif-result'; const LOCK_FILES_TO_MANIFEST_MAP = { 'Gemfile.lock': 'Gemfile', @@ -89,45 +90,6 @@ ${vuln.description}`.replace(/##\s/g, '# '), ); } -export function getResults(testResult): sarif.Result[] { - const groupedVulnerabilities = groupBy(testResult.vulnerabilities, 'id'); - return map( - groupedVulnerabilities, - ([vuln]): sarif.Result => ({ - ruleId: vuln.id, - level: getLevel(vuln), - message: { - text: `This file introduces a vulnerable ${vuln.packageName} package with a ${vuln.severity} severity vulnerability.`, - }, - locations: [ - { - physicalLocation: { - artifactLocation: { - uri: testResult.displayTargetFile, - }, - region: { - startLine: vuln.lineNumber || 1, - }, - }, - }, - ], - }), - ); -} - -export function getLevel(vuln: AnnotatedIssue) { - switch (vuln.severity) { - case SEVERITY.CRITICAL: - case SEVERITY.HIGH: - return 'error'; - case SEVERITY.MEDIUM: - return 'warning'; - case SEVERITY.LOW: - default: - return 'note'; - } -} - function getIntroducedThrough(vuln: AnnotatedIssue) { const [firstFrom, secondFrom] = vuln.from || []; diff --git a/src/lib/formatters/sarif-output.ts b/src/lib/formatters/sarif-output.ts index d40d501a00..c01001646a 100644 --- a/src/lib/formatters/sarif-output.ts +++ b/src/lib/formatters/sarif-output.ts @@ -1,12 +1,15 @@ import * as sarif from 'sarif'; +import * as upperFirst from 'lodash.upperfirst'; import { TestResult } from '../snyk-test/legacy'; import { SEVERITY } from '../snyk-test/legacy'; -const upperFirst = require('lodash.upperfirst'); +import { getResults } from './get-sarif-result'; export function createSarifOutputForContainers( testResults: TestResult[], ): sarif.Log { const sarifRes: sarif.Log = { + $schema: + 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json', version: '2.1.0', runs: [], }; @@ -48,7 +51,7 @@ export function getTool(testResult): sarif.Tool { return; } const level = getIssueLevel(vuln.severity); - const cve = vuln['identifiers']['CVE'][0]; + const cve = vuln.identifiers?.CVE?.join(); pushedIds[vuln.id] = true; return { id: vuln.id, @@ -70,39 +73,15 @@ export function getTool(testResult): sarif.Tool { level: level, }, properties: { - tags: ['security', ...vuln.identifiers.CWE], + tags: [ + 'security', + ...(vuln.identifiers?.CWE || []), + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + testResult.packageManager!, + ], }, }; }) .filter(Boolean); return tool; } - -export function getResults(testResult): sarif.Result[] { - const results: sarif.Result[] = []; - - if (!testResult.vulnerabilities) { - return results; - } - testResult.vulnerabilities.forEach((vuln) => { - results.push({ - ruleId: vuln.id, - message: { - text: `This file introduces a vulnerable ${vuln.packageName} package with a ${vuln.severity} severity vulnerability.`, - }, - locations: [ - { - physicalLocation: { - artifactLocation: { - uri: testResult.displayTargetFile, - }, - region: { - startLine: vuln.lineNumber || 1, - }, - }, - }, - ], - }); - }); - return results; -} diff --git a/test/fixtures/docker/sarif-container-result.json b/test/fixtures/docker/sarif-container-result.json index 4835d81393..024f9d8c22 100644 --- a/test/fixtures/docker/sarif-container-result.json +++ b/test/fixtures/docker/sarif-container-result.json @@ -1,4 +1,5 @@ { + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", "version": "2.1.0", "runs": [ { @@ -18,8 +19,15 @@ "text": "", "markdown": "## Overview\nUse-after-free vulnerability in bzip2recover in bzip2 1.0.6 allows remote attackers to cause a denial of service (crash) via a crafted bzip2 file, related to block ends set to before the start of the block.\n\n## References\n- [GENTOO](https://security.gentoo.org/glsa/201708-08)\n- [CONFIRM](https://bugzilla.redhat.com/show_bug.cgi?id=1319648)\n- [SECTRACK](http://www.securitytracker.com/id/1036132)\n- [BID](http://www.securityfocus.com/bid/91297)\n- [CONFIRM](http://www.oracle.com/technetwork/topics/security/bulletinjul2016-3090568.html)\n- [MLIST](http://www.openwall.com/lists/oss-security/2016/06/20/1)\n" }, - "defaultConfiguration": { "level": "warning" }, - "properties": { "tags": ["security"] } + "defaultConfiguration": { + "level": "warning" + }, + "properties": { + "tags": [ + "security", + "deb" + ] + } } ] } @@ -27,6 +35,7 @@ "results": [ { "ruleId": "SNYK-LINUX-BZIP2-106947", + "level": "note", "message": { "text": "This file introduces a vulnerable bzip2 package with a low severity vulnerability." }, @@ -34,21 +43,9 @@ { "physicalLocation": { "artifactLocation": {}, - "region": { "startLine": 1 } - } - } - ] - }, - { - "ruleId": "SNYK-LINUX-BZIP2-106947", - "message": { - "text": "This file introduces a vulnerable bzip2 package with a low severity vulnerability." - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": {}, - "region": { "startLine": 1 } + "region": { + "startLine": 1 + } } } ] diff --git a/test/jest/unit/lib/formatters/__snapshots__/sarif-output.spec.ts.snap b/test/jest/unit/lib/formatters/__snapshots__/sarif-output.spec.ts.snap index a554ade2cb..950826a11d 100644 --- a/test/jest/unit/lib/formatters/__snapshots__/sarif-output.spec.ts.snap +++ b/test/jest/unit/lib/formatters/__snapshots__/sarif-output.spec.ts.snap @@ -1,11 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`createSarifOutputForContainers general with critical severity issue 1`] = ` +exports[`createSarifOutputForContainers general with critical severity issue without CVE 1`] = ` Object { + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", "runs": Array [ Object { "results": Array [ Object { + "level": "error", "locations": Array [ Object { "physicalLocation": Object { @@ -33,7 +35,7 @@ Object { "level": "error", }, "fullDescription": Object { - "text": "(CVE-2018-20843) expat@2.2.5-r0", + "text": "expat@2.2.5-r0", }, "help": Object { "markdown": "## Overview @@ -62,6 +64,86 @@ In libexpat in Expat before 2.2.7, XML input including XML names that contain a "tags": Array [ "security", "CWE-611", + "npm", + ], + }, + "shortDescription": Object { + "text": "Critical severity - XML External Entity (XXE) Injection vulnerability in expat", + }, + }, + ], + }, + }, + }, + ], + "version": "2.1.0", +} +`; + +exports[`createSarifOutputForContainers general with critical severity issue without CWE 1`] = ` +Object { + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + "runs": Array [ + Object { + "results": Array [ + Object { + "level": "error", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "uri": undefined, + }, + "region": Object { + "startLine": 1, + }, + }, + }, + ], + "message": Object { + "text": "This file introduces a vulnerable expat package with a critical severity vulnerability.", + }, + "ruleId": "SNYK-LINUX-EXPAT-450908", + }, + ], + "tool": Object { + "driver": Object { + "name": "Snyk Container", + "rules": Array [ + Object { + "defaultConfiguration": Object { + "level": "error", + }, + "fullDescription": Object { + "text": "(CVE-2018-20843) expat@2.2.5-r0", + }, + "help": Object { + "markdown": "## Overview +In libexpat in Expat before 2.2.7, XML input including XML names that contain a large number of colons could make the XML parser consume a high amount of RAM and CPU resources while processing (enough to be usable for denial-of-service attacks). + +## References +- [Bugtraq Mailing List](https://seclists.org/bugtraq/2019/Jun/39) +- [CVE Details](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-20843) +- [Debian Security Advisory](https://www.debian.org/security/2019/dsa-4472) +- [Debian Security Announcement](https://lists.debian.org/debian-lts-announce/2019/06/msg00028.html) +- [Debian Security Tracker](https://security-tracker.debian.org/tracker/CVE-2018-20843) +- [GitHub Commit](https://github.com/libexpat/libexpat/pull/262/commits/11f8838bf99ea0a6f0b76f9760c43704d00c4ff6) +- [GitHub Issue](https://github.com/libexpat/libexpat/issues/186) +- [GitHub PR](https://github.com/libexpat/libexpat/pull/262) +- [MISC](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=5226) +- [MISC](https://github.com/libexpat/libexpat/blob/R_2_2_7/expat/Changes) +- [Netapp Security Advisory](https://security.netapp.com/advisory/ntap-20190703-0001/) +- [Ubuntu CVE Tracker](http://people.ubuntu.com/~ubuntu-security/cve/CVE-2018-20843) +- [Ubuntu Security Advisory](https://usn.ubuntu.com/4040-1/) +- [Ubuntu Security Advisory](https://usn.ubuntu.com/4040-2/) +", + "text": "", + }, + "id": "SNYK-LINUX-EXPAT-450908", + "properties": Object { + "tags": Array [ + "security", + "npm", ], }, "shortDescription": Object { @@ -79,10 +161,12 @@ In libexpat in Expat before 2.2.7, XML input including XML names that contain a exports[`createSarifOutputForContainers general with high severity issue 1`] = ` Object { + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", "runs": Array [ Object { "results": Array [ Object { + "level": "error", "locations": Array [ Object { "physicalLocation": Object { @@ -139,6 +223,7 @@ In libexpat in Expat before 2.2.7, XML input including XML names that contain a "tags": Array [ "security", "CWE-611", + "npm", ], }, "shortDescription": Object { diff --git a/test/jest/unit/lib/formatters/sarif-output.spec.ts b/test/jest/unit/lib/formatters/sarif-output.spec.ts index cb75f52250..4e60f4ef95 100644 --- a/test/jest/unit/lib/formatters/sarif-output.spec.ts +++ b/test/jest/unit/lib/formatters/sarif-output.spec.ts @@ -4,19 +4,91 @@ import { SupportedProjectTypes } from '../../../../../src/lib/types'; describe('createSarifOutputForContainers', () => { it('general with high severity issue', () => { - const testFile = getTestResult(SEVERITY.HIGH); + const identifiers = { + ALTERNATIVE: [ + 'SNYK-DEBIAN8-EXPAT-450909', + 'SNYK-DEBIAN9-EXPAT-450910', + 'SNYK-DEBIANUNSTABLE-EXPAT-450911', + 'SNYK-DEBIAN10-EXPAT-450912', + 'SNYK-UBUNTU1404-EXPAT-451027', + 'SNYK-UBUNTU1204-EXPAT-451028', + 'SNYK-UBUNTU1810-EXPAT-451029', + 'SNYK-UBUNTU1604-EXPAT-451030', + 'SNYK-UBUNTU1804-EXPAT-451031', + 'SNYK-ALPINE38-EXPAT-451858', + 'SNYK-ALPINE39-EXPAT-453353', + 'SNYK-ALPINE37-EXPAT-453374', + 'SNYK-ALPINE310-EXPAT-453902', + 'SNYK-DEBIAN11-EXPAT-518187', + 'SNYK-UBUNTU1904-EXPAT-531483', + ], + CVE: ['CVE-2018-20843'], + CWE: ['CWE-611'], + }; + const testFile = getTestResult(SEVERITY.HIGH, identifiers); const sarif = createSarifOutputForContainers([testFile]); expect(sarif).toMatchSnapshot(); }); - it('general with critical severity issue', () => { - const testFile = getTestResult(SEVERITY.CRITICAL); + it('general with critical severity issue without CVE', () => { + const identifiersWithoutCVE = { + ALTERNATIVE: [ + 'SNYK-DEBIAN8-EXPAT-450909', + 'SNYK-DEBIAN9-EXPAT-450910', + 'SNYK-DEBIANUNSTABLE-EXPAT-450911', + 'SNYK-DEBIAN10-EXPAT-450912', + 'SNYK-UBUNTU1404-EXPAT-451027', + 'SNYK-UBUNTU1204-EXPAT-451028', + 'SNYK-UBUNTU1810-EXPAT-451029', + 'SNYK-UBUNTU1604-EXPAT-451030', + 'SNYK-UBUNTU1804-EXPAT-451031', + 'SNYK-ALPINE38-EXPAT-451858', + 'SNYK-ALPINE39-EXPAT-453353', + 'SNYK-ALPINE37-EXPAT-453374', + 'SNYK-ALPINE310-EXPAT-453902', + 'SNYK-DEBIAN11-EXPAT-518187', + 'SNYK-UBUNTU1904-EXPAT-531483', + ], + CWE: ['CWE-611'], + }; + const testFile = getTestResult(SEVERITY.CRITICAL, identifiersWithoutCVE); + const sarif = createSarifOutputForContainers([testFile]); + expect(sarif).toMatchSnapshot(); + }); + + it('general with critical severity issue without CWE', () => { + const identifiersWithoutCWE = { + ALTERNATIVE: [ + 'SNYK-DEBIAN8-EXPAT-450909', + 'SNYK-DEBIAN9-EXPAT-450910', + 'SNYK-DEBIANUNSTABLE-EXPAT-450911', + 'SNYK-DEBIAN10-EXPAT-450912', + 'SNYK-UBUNTU1404-EXPAT-451027', + 'SNYK-UBUNTU1204-EXPAT-451028', + 'SNYK-UBUNTU1810-EXPAT-451029', + 'SNYK-UBUNTU1604-EXPAT-451030', + 'SNYK-UBUNTU1804-EXPAT-451031', + 'SNYK-ALPINE38-EXPAT-451858', + 'SNYK-ALPINE39-EXPAT-453353', + 'SNYK-ALPINE37-EXPAT-453374', + 'SNYK-ALPINE310-EXPAT-453902', + 'SNYK-DEBIAN11-EXPAT-518187', + 'SNYK-UBUNTU1904-EXPAT-531483', + ], + CVE: ['CVE-2018-20843'], + }; + const testFile = getTestResult(SEVERITY.CRITICAL, identifiersWithoutCWE); const sarif = createSarifOutputForContainers([testFile]); expect(sarif).toMatchSnapshot(); }); }); -function getTestResult(severity: SEVERITY): TestResult { +function getTestResult( + severity: SEVERITY, + identifiers?: { + [name: string]: string[]; + }, +): TestResult { return { vulnerabilities: [ { @@ -24,27 +96,7 @@ function getTestResult(severity: SEVERITY): TestResult { description: '## Overview\nIn libexpat in Expat before 2.2.7, XML input including XML names that contain a large number of colons could make the XML parser consume a high amount of RAM and CPU resources while processing (enough to be usable for denial-of-service attacks).\n\n## References\n- [Bugtraq Mailing List](https://seclists.org/bugtraq/2019/Jun/39)\n- [CVE Details](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-20843)\n- [Debian Security Advisory](https://www.debian.org/security/2019/dsa-4472)\n- [Debian Security Announcement](https://lists.debian.org/debian-lts-announce/2019/06/msg00028.html)\n- [Debian Security Tracker](https://security-tracker.debian.org/tracker/CVE-2018-20843)\n- [GitHub Commit](https://github.com/libexpat/libexpat/pull/262/commits/11f8838bf99ea0a6f0b76f9760c43704d00c4ff6)\n- [GitHub Issue](https://github.com/libexpat/libexpat/issues/186)\n- [GitHub PR](https://github.com/libexpat/libexpat/pull/262)\n- [MISC](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=5226)\n- [MISC](https://github.com/libexpat/libexpat/blob/R_2_2_7/expat/Changes)\n- [Netapp Security Advisory](https://security.netapp.com/advisory/ntap-20190703-0001/)\n- [Ubuntu CVE Tracker](http://people.ubuntu.com/~ubuntu-security/cve/CVE-2018-20843)\n- [Ubuntu Security Advisory](https://usn.ubuntu.com/4040-1/)\n- [Ubuntu Security Advisory](https://usn.ubuntu.com/4040-2/)\n', id: 'SNYK-LINUX-EXPAT-450908', - identifiers: { - ALTERNATIVE: [ - 'SNYK-DEBIAN8-EXPAT-450909', - 'SNYK-DEBIAN9-EXPAT-450910', - 'SNYK-DEBIANUNSTABLE-EXPAT-450911', - 'SNYK-DEBIAN10-EXPAT-450912', - 'SNYK-UBUNTU1404-EXPAT-451027', - 'SNYK-UBUNTU1204-EXPAT-451028', - 'SNYK-UBUNTU1810-EXPAT-451029', - 'SNYK-UBUNTU1604-EXPAT-451030', - 'SNYK-UBUNTU1804-EXPAT-451031', - 'SNYK-ALPINE38-EXPAT-451858', - 'SNYK-ALPINE39-EXPAT-453353', - 'SNYK-ALPINE37-EXPAT-453374', - 'SNYK-ALPINE310-EXPAT-453902', - 'SNYK-DEBIAN11-EXPAT-518187', - 'SNYK-UBUNTU1904-EXPAT-531483', - ], - CVE: ['CVE-2018-20843'], - CWE: ['CWE-611'], - }, + identifiers, packageManager: 'linux' as SupportedProjectTypes, packageName: 'expat', patches: [],