diff --git a/src/lib/formatters/test/format-test-results.ts b/src/lib/formatters/test/format-test-results.ts index 7fb6d1b1a8b..9369ac46a0c 100644 --- a/src/lib/formatters/test/format-test-results.ts +++ b/src/lib/formatters/test/format-test-results.ts @@ -29,6 +29,11 @@ import { jsonStringifyLargeObject } from '../../json'; import { createSarifOutputForOpenSource } from '../open-source-sarif-output'; import { getSeverityValue } from '../get-severity-value'; import { showFixTip } from '../show-fix-tip'; +import { + DockerFileAnalysisErrorCode, + facts as dockerFacts, +} from 'snyk-docker-plugin/dist'; +import { ScanResult } from '../../ecosystems/types'; export function formatJsonOutput(jsonData, options: Options) { const jsonDataClone = cloneDeep(jsonData); @@ -159,6 +164,7 @@ export function getDisplayedOutput( const fixTip = showFixTip(projectType, res, options); const fixAdvice = fixTip ? `\n\n${fixTip}` : ''; + const dockerfileWarning = getDockerfileWarning(res.scanResult); const dockerSuggestion = getDockerSuggestionText(options, config); const vulns = res.vulnerabilities || []; @@ -220,6 +226,7 @@ export function getDisplayedOutput( multiProjAdvice + ignoredIssues + dockerAdvice + + dockerfileWarning + dockerSuggestion + dockerCTA ); @@ -257,6 +264,43 @@ function getDockerSuggestionText(options, config): string { return dockerSuggestion; } +function getDockerfileWarning(scanResult: ScanResult | undefined): string { + if (!scanResult) { + return ''; + } + + const fact = scanResult.facts.find( + (fact) => fact.type === 'dockerfileAnalysis', + ); + if (!fact) { + return ''; + } + + const dockerfileAnalysisFact = fact as dockerFacts.DockerfileAnalysisFact; + if (!dockerfileAnalysisFact.data.error) { + return ''; + } + + let userMessage = chalk.yellow( + '\n\nWarning: Unable to analyse Dockerfile provided through `--file`.', + ); + + switch (dockerfileAnalysisFact.data.error.code) { + case DockerFileAnalysisErrorCode.BASE_IMAGE_NAME_NOT_FOUND: + userMessage += chalk.yellow( + '\n Dockerfile must begin with a FROM instruction. This may be after parser directives, comments, and globally scoped ARGs.', + ); + break; + case DockerFileAnalysisErrorCode.BASE_IMAGE_NON_RESOLVABLE: + userMessage += chalk.yellow( + '\n Dockerfile must have default values for all ARG instructions.', + ); + break; + } + + return userMessage; +} + export function groupVulnerabilities( vulns, ): { diff --git a/test/acceptance/workspaces/fail-on/docker/warning/dockerfile-base-image-name-not-found.json b/test/acceptance/workspaces/fail-on/docker/warning/dockerfile-base-image-name-not-found.json new file mode 100644 index 00000000000..865a5aea5e7 --- /dev/null +++ b/test/acceptance/workspaces/fail-on/docker/warning/dockerfile-base-image-name-not-found.json @@ -0,0 +1,104 @@ +{ + "vulnerabilities": [ + { + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "creationTime": "2019-08-06T22:04:52.027240Z", + "credit": [""], + "cvssScore": 9.8, + "description": "## Overview\nmusl libc through 1.1.23 has an x87 floating-point stack adjustment imbalance, related to the math/i386/ directory. In some cases, use of this library could introduce out-of-bounds writes that are not present in an application's source code.\n\n## References\n- [Debian Security Tracker](https://security-tracker.debian.org/tracker/CVE-2019-14697)\n- [MISC](https://www.openwall.com/lists/musl/2019/08/06/1)\n- [OSS security Advisory](http://www.openwall.com/lists/oss-security/2019/08/06/4)\n", + "disclosureTime": "2019-08-06T16:15:00Z", + "id": "SNYK-LINUX-MUSL-458116", + "identifiers": { + "ALTERNATIVE": [ + "SNYK-DEBIANUNSTABLE-MUSL-458117", + "SNYK-DEBIAN9-MUSL-458118", + "SNYK-DEBIAN10-MUSL-458127", + "SNYK-DEBIAN8-MUSL-458128", + "SNYK-ALPINE38-MUSL-458276", + "SNYK-ALPINE37-MUSL-458286", + "SNYK-ALPINE310-MUSL-458452", + "SNYK-ALPINE39-MUSL-458529", + "SNYK-DEBIAN11-MUSL-522584" + ], + "CVE": ["CVE-2019-14697"], + "CWE": ["CWE-787"] + }, + "language": "linux", + "modificationTime": "2019-11-04T18:03:52.721307Z", + "packageManager": "linux", + "packageName": "musl", + "patches": [], + "publicationTime": "2019-08-06T22:04:52.037600Z", + "references": [ + { + "title": "Debian Security Tracker", + "url": "https://security-tracker.debian.org/tracker/CVE-2019-14697" + }, + { + "title": "MISC", + "url": "https://www.openwall.com/lists/musl/2019/08/06/1" + }, + { + "title": "OSS security Advisory", + "url": "http://www.openwall.com/lists/oss-security/2019/08/06/4" + } + ], + "semver": { + "vulnerableByDistro": { + "alpine:3.10": ["<1.1.22-r3"], + "alpine:3.7": ["<1.1.18-r4"], + "alpine:3.8": ["<1.1.19-r11"], + "alpine:3.9": ["<1.1.20-r5"], + "debian:10": ["*"], + "debian:11": ["<1.1.23-2"], + "debian:8": ["*"], + "debian:9": ["*"], + "debian:unstable": ["<1.1.23-2"] + }, + "vulnerable": ["<1.1.19-r11"] + }, + "severity": "high", + "title": "Out-of-bounds Write", + "from": [ + "docker-image|garethr/snyky@alpine", + "meta-common-packages@meta", + "musl@1.1.19-r10" + ], + "upgradePath": [], + "isUpgradable": false, + "isPatchable": false, + "name": "musl", + "version": "1.1.19-r10", + "nearestFixedInVersion": "1.1.19-r11" + } + ], + "ok": false, + "dependencyCount": 40, + "org": "test-organization", + "policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.14.0\nignore: {}\npatch: {}\n", + "isPrivate": true, + "licensesPolicy": { "severities": {}, "orgLicenseRules": {} }, + "ignoreSettings": null, + "docker": { "binariesVulns": { "issuesData": {}, "affectedPkgs": {} } }, + "summary": "7 vulnerable dependency paths", + "filesystemPolicy": false, + "filtered": { "ignore": [], "patch": [] }, + "uniqueCount": 1, + "packageManager": "apk", + "targetFile": "Dockerfile", + "projectName": "alpine", + "platform": "linux/amd64", + "scanResult": { + "facts": [ + { + "type": "dockerfileAnalysis", + "data": { + "error": { + "code": "BASE_IMAGE_NAME_NOT_FOUND" + } + } + } + ] + } + } + \ No newline at end of file diff --git a/test/acceptance/workspaces/fail-on/docker/warning/dockerfile-base-image-non-resolvable.json b/test/acceptance/workspaces/fail-on/docker/warning/dockerfile-base-image-non-resolvable.json new file mode 100644 index 00000000000..1cdef9a0637 --- /dev/null +++ b/test/acceptance/workspaces/fail-on/docker/warning/dockerfile-base-image-non-resolvable.json @@ -0,0 +1,104 @@ +{ + "vulnerabilities": [ + { + "CVSSv3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", + "creationTime": "2019-08-06T22:04:52.027240Z", + "credit": [""], + "cvssScore": 9.8, + "description": "## Overview\nmusl libc through 1.1.23 has an x87 floating-point stack adjustment imbalance, related to the math/i386/ directory. In some cases, use of this library could introduce out-of-bounds writes that are not present in an application's source code.\n\n## References\n- [Debian Security Tracker](https://security-tracker.debian.org/tracker/CVE-2019-14697)\n- [MISC](https://www.openwall.com/lists/musl/2019/08/06/1)\n- [OSS security Advisory](http://www.openwall.com/lists/oss-security/2019/08/06/4)\n", + "disclosureTime": "2019-08-06T16:15:00Z", + "id": "SNYK-LINUX-MUSL-458116", + "identifiers": { + "ALTERNATIVE": [ + "SNYK-DEBIANUNSTABLE-MUSL-458117", + "SNYK-DEBIAN9-MUSL-458118", + "SNYK-DEBIAN10-MUSL-458127", + "SNYK-DEBIAN8-MUSL-458128", + "SNYK-ALPINE38-MUSL-458276", + "SNYK-ALPINE37-MUSL-458286", + "SNYK-ALPINE310-MUSL-458452", + "SNYK-ALPINE39-MUSL-458529", + "SNYK-DEBIAN11-MUSL-522584" + ], + "CVE": ["CVE-2019-14697"], + "CWE": ["CWE-787"] + }, + "language": "linux", + "modificationTime": "2019-11-04T18:03:52.721307Z", + "packageManager": "linux", + "packageName": "musl", + "patches": [], + "publicationTime": "2019-08-06T22:04:52.037600Z", + "references": [ + { + "title": "Debian Security Tracker", + "url": "https://security-tracker.debian.org/tracker/CVE-2019-14697" + }, + { + "title": "MISC", + "url": "https://www.openwall.com/lists/musl/2019/08/06/1" + }, + { + "title": "OSS security Advisory", + "url": "http://www.openwall.com/lists/oss-security/2019/08/06/4" + } + ], + "semver": { + "vulnerableByDistro": { + "alpine:3.10": ["<1.1.22-r3"], + "alpine:3.7": ["<1.1.18-r4"], + "alpine:3.8": ["<1.1.19-r11"], + "alpine:3.9": ["<1.1.20-r5"], + "debian:10": ["*"], + "debian:11": ["<1.1.23-2"], + "debian:8": ["*"], + "debian:9": ["*"], + "debian:unstable": ["<1.1.23-2"] + }, + "vulnerable": ["<1.1.19-r11"] + }, + "severity": "high", + "title": "Out-of-bounds Write", + "from": [ + "docker-image|garethr/snyky@alpine", + "meta-common-packages@meta", + "musl@1.1.19-r10" + ], + "upgradePath": [], + "isUpgradable": false, + "isPatchable": false, + "name": "musl", + "version": "1.1.19-r10", + "nearestFixedInVersion": "1.1.19-r11" + } + ], + "ok": false, + "dependencyCount": 40, + "org": "test-organization", + "policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.14.0\nignore: {}\npatch: {}\n", + "isPrivate": true, + "licensesPolicy": { "severities": {}, "orgLicenseRules": {} }, + "ignoreSettings": null, + "docker": { "binariesVulns": { "issuesData": {}, "affectedPkgs": {} } }, + "summary": "7 vulnerable dependency paths", + "filesystemPolicy": false, + "filtered": { "ignore": [], "patch": [] }, + "uniqueCount": 1, + "packageManager": "apk", + "targetFile": "Dockerfile", + "projectName": "alpine", + "platform": "linux/amd64", + "scanResult": { + "facts": [ + { + "type": "dockerfileAnalysis", + "data": { + "error": { + "code": "BASE_IMAGE_NON_RESOLVABLE" + } + } + } + ] + } + } + \ No newline at end of file diff --git a/test/jest/unit/lib/formatters/test/__snapshots__/display-result.spec.ts.snap b/test/jest/unit/lib/formatters/test/__snapshots__/display-result.spec.ts.snap index 9beb73f0e7b..66539c803b9 100644 --- a/test/jest/unit/lib/formatters/test/__snapshots__/display-result.spec.ts.snap +++ b/test/jest/unit/lib/formatters/test/__snapshots__/display-result.spec.ts.snap @@ -52,6 +52,72 @@ Example: $ snyk test --docker src --file=path/to/Dockerfile To remove this message in the future, please run \`snyk config set disableSuggestions=true\`" `; +exports[`displayResult Docker test result with base image name not found warning 1`] = ` +" +Testing alpine:latest... + +✗ High severity vulnerability found in musl + Description: Out-of-bounds Write + Info: [URL] + Introduced through: meta-common-packages@meta + From: meta-common-packages@meta > musl@1.1.19-r10 + Fixed in: 1.1.19-r11 + + + +Organization: test-organization +Package manager: apk +Target file: Dockerfile +Project name: alpine +Docker image: alpine:latest +Platform: linux/amd64 +Licenses: enabled + +Tested 40 dependencies for known issues, found 1 issue. + +Tip: Detected multiple supported manifests (1), use --all-projects to scan all of them at once. + +Warning: Unable to analyse Dockerfile provided through \`--file\`. + Dockerfile must begin with a FROM instruction. This may be after parser directives, comments, and globally scoped ARGs. + +Pro tip: use \`--exclude-base-image-vulns\` to exclude from display Docker base image vulnerabilities. + +To remove this message in the future, please run \`snyk config set disableSuggestions=true\`" +`; + +exports[`displayResult Docker test result with base image non resolvable warning 1`] = ` +" +Testing alpine:latest... + +✗ High severity vulnerability found in musl + Description: Out-of-bounds Write + Info: [URL] + Introduced through: meta-common-packages@meta + From: meta-common-packages@meta > musl@1.1.19-r10 + Fixed in: 1.1.19-r11 + + + +Organization: test-organization +Package manager: apk +Target file: Dockerfile +Project name: alpine +Docker image: alpine:latest +Platform: linux/amd64 +Licenses: enabled + +Tested 40 dependencies for known issues, found 1 issue. + +Tip: Detected multiple supported manifests (1), use --all-projects to scan all of them at once. + +Warning: Unable to analyse Dockerfile provided through \`--file\`. + Dockerfile must have default values for all ARG instructions. + +Pro tip: use \`--exclude-base-image-vulns\` to exclude from display Docker base image vulnerabilities. + +To remove this message in the future, please run \`snyk config set disableSuggestions=true\`" +`; + exports[`displayResult Pip result with pins 1`] = ` " Testing src... diff --git a/test/jest/unit/lib/formatters/test/display-result.spec.ts b/test/jest/unit/lib/formatters/test/display-result.spec.ts index 30f4491d8cc..c09f30d8405 100644 --- a/test/jest/unit/lib/formatters/test/display-result.spec.ts +++ b/test/jest/unit/lib/formatters/test/display-result.spec.ts @@ -24,6 +24,56 @@ describe('displayResult', () => { expect(stripAnsi(res).replace(/http.*/g, '[URL]')).toMatchSnapshot(); }); + it('Docker test result with base image non resolvable warning', () => { + const withWarning = JSON.parse( + fs.readFileSync( + path.resolve( + __dirname, + '../../../../../', + 'acceptance/workspaces/fail-on/docker/warning/dockerfile-base-image-non-resolvable.json', + ), + 'utf8', + ), + ); + + const res = displayResult( + withWarning, + { + showVulnPaths: 'all', + file: 'Dockerfile', + path: 'alpine:latest', + docker: true, + }, + 1, + ); + expect(stripAnsi(res).replace(/http.*/g, '[URL]')).toMatchSnapshot(); + }); + + it('Docker test result with base image name not found warning', () => { + const withWarning = JSON.parse( + fs.readFileSync( + path.resolve( + __dirname, + '../../../../../', + 'acceptance/workspaces/fail-on/docker/warning/dockerfile-base-image-name-not-found.json', + ), + 'utf8', + ), + ); + + const res = displayResult( + withWarning, + { + showVulnPaths: 'all', + file: 'Dockerfile', + path: 'alpine:latest', + docker: true, + }, + 1, + ); + expect(stripAnsi(res).replace(/http.*/g, '[URL]')).toMatchSnapshot(); + }); + it('Pip result with pins', () => { const withRemediation = JSON.parse( fs.readFileSync(