From 51c75d4e30bd990e0c23302366de26f8d6224b84 Mon Sep 17 00:00:00 2001 From: ghe Date: Wed, 10 Jun 2020 12:25:31 +0100 Subject: [PATCH 1/9] feat: introduce yarn workspaces scanning test & monitor --- src/cli/args.ts | 1 + .../formatters/format-monitor-response.ts | 3 - src/cli/commands/monitor/index.ts | 2 +- src/cli/index.ts | 6 + src/lib/options-validator.ts | 2 +- src/lib/plugins/get-deps-from-plugin.ts | 25 +- .../nodejs-plugin/yarn-workspaces-parser.ts | 136 +++++ src/lib/reachable-vulns.ts | 1 + src/lib/snyk-test/index.js | 9 +- src/lib/snyk-test/run-test.ts | 4 +- src/lib/types.ts | 3 + test/acceptance/cli-args.test.ts | 1 + .../cli-test/cli-test.yarn-workspaces.spec.ts | 93 ++++ .../workspaces/yarn-workspaces/package.json | 19 + .../packages/apples/package.json | 20 + .../packages/tomatoes/package.json | 10 + .../workspaces/yarn-workspaces/yarn.lock | 501 ++++++++++++++++++ 17 files changed, 820 insertions(+), 16 deletions(-) create mode 100644 src/lib/plugins/nodejs-plugin/yarn-workspaces-parser.ts create mode 100644 test/acceptance/cli-test/cli-test.yarn-workspaces.spec.ts create mode 100644 test/acceptance/workspaces/yarn-workspaces/package.json create mode 100644 test/acceptance/workspaces/yarn-workspaces/packages/apples/package.json create mode 100644 test/acceptance/workspaces/yarn-workspaces/packages/tomatoes/package.json create mode 100644 test/acceptance/workspaces/yarn-workspaces/yarn.lock diff --git a/src/cli/args.ts b/src/cli/args.ts index 121bd4fff5c..9bc7d51ae53 100644 --- a/src/cli/args.ts +++ b/src/cli/args.ts @@ -181,6 +181,7 @@ export function args(rawArgv: string[]): Args { 'scan-all-unmanaged', 'fail-on', 'all-projects', + 'yarn-workspaces', 'detection-depth', 'reachable-vulns', ]) { diff --git a/src/cli/commands/monitor/formatters/format-monitor-response.ts b/src/cli/commands/monitor/formatters/format-monitor-response.ts index 78bd6a52b47..aa700598a39 100644 --- a/src/cli/commands/monitor/formatters/format-monitor-response.ts +++ b/src/cli/commands/monitor/formatters/format-monitor-response.ts @@ -22,9 +22,6 @@ export function formatMonitorOutput( : res.path; const strOutput = chalk.bold.white('\nMonitoring ' + humanReadableName + '...\n\n') + - (packageManager === 'yarn' - ? 'A yarn.lock file was detected - continuing as a Yarn project.\n' - : '') + 'Explore this snapshot at ' + res.uri + '\n\n' + diff --git a/src/cli/commands/monitor/index.ts b/src/cli/commands/monitor/index.ts index 723195b89eb..e6795a7b095 100644 --- a/src/cli/commands/monitor/index.ts +++ b/src/cli/commands/monitor/index.ts @@ -120,7 +120,7 @@ async function monitor(...args0: MethodArgs): Promise { validateMonitorPath(path, options.docker); let analysisType = 'all'; let packageManager; - if (options.allProjects) { + if (options.allProjects || options.yarnWorkspaces) { analysisType = 'all'; } else if (options.docker) { analysisType = 'docker'; diff --git a/src/cli/index.ts b/src/cli/index.ts index f7de0ebaaf4..79a800949a4 100755 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -244,6 +244,12 @@ async function main() { if (args.options.file && args.options.allProjects) { throw new UnsupportedOptionCombinationError(['file', 'all-projects']); } + if (args.options.yarnWorkspaces && args.options.allProjects) { + throw new UnsupportedOptionCombinationError([ + 'yarn-workspaces', + 'all-projects', + ]); + } if (args.options.packageManager && args.options.allProjects) { throw new UnsupportedOptionCombinationError([ 'package-manager', diff --git a/src/lib/options-validator.ts b/src/lib/options-validator.ts index b71067e0619..7abd5f9f352 100644 --- a/src/lib/options-validator.ts +++ b/src/lib/options-validator.ts @@ -9,7 +9,7 @@ export async function validateOptions( ): Promise { if (options.reachableVulns) { // Throwing error only in case when both packageManager and allProjects not defined - if (!packageManager && !options.allProjects) { + if (!packageManager && !options.allProjects && !options.yarnWorkspaces) { throw new Error('Could not determine package manager'); } const org = options.org || config.org; diff --git a/src/lib/plugins/get-deps-from-plugin.ts b/src/lib/plugins/get-deps-from-plugin.ts index d6419475c11..807907a5ed8 100644 --- a/src/lib/plugins/get-deps-from-plugin.ts +++ b/src/lib/plugins/get-deps-from-plugin.ts @@ -13,9 +13,21 @@ import { import analytics = require('../analytics'); import { convertSingleResultToMultiCustom } from './convert-single-splugin-res-to-multi-custom'; import { convertMultiResultToMultiCustom } from './convert-multi-plugin-res-to-multi-custom'; +import { processYarnWorkspaces } from './nodejs-plugin/yarn-workspaces-parser'; const debug = debugModule('snyk-test'); +const multiProjectProcessors = { + yarnWorkspaces: { + handler: processYarnWorkspaces, + files: ['package.json'], + }, + allProjects: { + handler: getMultiPluginResult, + files: AUTO_DETECTABLE_FILES, + }, +}; + // Force getDepsFromPlugin to return scannedProjects for processing export async function getDepsFromPlugin( root: string, @@ -23,13 +35,14 @@ export async function getDepsFromPlugin( ): Promise { let inspectRes: pluginApi.InspectResult; - if (options.allProjects) { + if (Object.keys(multiProjectProcessors).some((key) => options[key])) { + const scanType = options.yarnWorkspaces ? 'yarnWorkspaces' : 'allProjects'; const levelsDeep = options.detectionDepth; const ignore = options.exclude ? options.exclude.split(',') : []; const targetFiles = await find( root, ignore, - AUTO_DETECTABLE_FILES, + multiProjectProcessors[scanType].files, levelsDeep, ); debug( @@ -39,7 +52,11 @@ export async function getDepsFromPlugin( if (targetFiles.length === 0) { throw NoSupportedManifestsFoundError([root]); } - inspectRes = await getMultiPluginResult(root, options, targetFiles); + inspectRes = await multiProjectProcessors[scanType].handler( + root, + options, + targetFiles, + ); const analyticData = { scannedProjects: inspectRes.scannedProjects.length, targetFiles, @@ -49,7 +66,7 @@ export async function getDepsFromPlugin( levelsDeep, ignore, }; - analytics.add('allProjects', analyticData); + analytics.add(scanType, analyticData); return inspectRes; } diff --git a/src/lib/plugins/nodejs-plugin/yarn-workspaces-parser.ts b/src/lib/plugins/nodejs-plugin/yarn-workspaces-parser.ts new file mode 100644 index 00000000000..5ca47e3d9a2 --- /dev/null +++ b/src/lib/plugins/nodejs-plugin/yarn-workspaces-parser.ts @@ -0,0 +1,136 @@ +import * as baseDebug from 'debug'; +const debug = baseDebug('yarn-workspaces'); +import * as fs from 'fs'; +import * as lockFileParser from 'snyk-nodejs-lockfile-parser'; +import * as path from 'path'; +import { NoSupportedManifestsFoundError } from '../../errors'; +import { + MultiProjectResultCustom, + ScannedProjectCustom, +} from '../get-multi-plugin-result'; + +export async function processYarnWorkspaces( + root: string, + settings: { + strictOutOfSync?: boolean; + scanDevDependencies?: boolean; + }, + targetFiles: string[], +): Promise { + const yarnTargetFiles = targetFiles.filter((f) => f.endsWith('package.json')); + debug(`processing Yarn workspaces (${targetFiles.length})`); + if (yarnTargetFiles.length === 0) { + throw NoSupportedManifestsFoundError([root]); + } + let yarnWorkspacesMap = {}; + const yarnWorkspacesFilesMap = {}; + let isYarnWorkspacePackage = false; + const result: MultiProjectResultCustom = { + plugin: { + name: 'snyk-nodejs-yarn-workspaces', + runtime: process.version, + }, + scannedProjects: [], + }; + for (const packageJsonFileName of yarnTargetFiles) { + const packageJson = getFileContents(root, packageJsonFileName); + yarnWorkspacesMap = { + ...yarnWorkspacesMap, + ...getWorkspacesMap(packageJson), + }; + + for (const workspaceRoot of Object.keys(yarnWorkspacesMap)) { + const workspaces = yarnWorkspacesMap[workspaceRoot].workspaces || []; + const match = workspaces + .map((pattern) => + packageJsonFileName.includes(pattern.replace(/\*/, '')), + ) + .filter(Boolean); + + if (match) { + yarnWorkspacesFilesMap[packageJsonFileName] = { + root: workspaceRoot, + }; + isYarnWorkspacePackage = true; + } + } + + if (isYarnWorkspacePackage) { + const rootDir = path.dirname( + yarnWorkspacesFilesMap[packageJsonFileName].root, + ); + const rootYarnLockfileName = path.join(rootDir, 'yarn.lock'); + + const yarnLock = await getFileContents(root, rootYarnLockfileName); + const res = await lockFileParser.buildDepTree( + packageJson.content, + yarnLock.content, + settings.scanDevDependencies, + lockFileParser.LockfileType.yarn, + settings.strictOutOfSync !== false, + ); + const project: ScannedProjectCustom = { + packageManager: 'yarn', + targetFile: path.parse(packageJson.name).base, + depTree: res as any, + plugin: { + name: 'snyk-nodejs-lockfile-parser', + runtime: process.version, + }, + }; + result.scannedProjects.push(project); + } + } + return result; +} + +function getFileContents( + root: string, + fileName: string, +): { + content: string; + name: string; +} { + const fullPath = path.resolve(root, fileName); + if (!fs.existsSync(fullPath)) { + throw new Error( + 'Manifest ' + fileName + ' not found at location: ' + fileName, + ); + } + const content = fs.readFileSync(fullPath, 'utf-8'); + return { + content, + name: fileName, + }; +} + +interface YarnWorkspacesMap { + [packageJsonName: string]: { + workspaces: string[]; + }; +} + +export function getWorkspacesMap(file: { + content: string; + name: string; +}): YarnWorkspacesMap { + const yarnWorkspacesMap = {}; + if (!file) { + return yarnWorkspacesMap; + } + + try { + const rootFileWorkspacesDefinitions = lockFileParser.getYarnWorkspaces( + file.content, + ); + + if (rootFileWorkspacesDefinitions && rootFileWorkspacesDefinitions.length) { + yarnWorkspacesMap[file.name] = { + workspaces: rootFileWorkspacesDefinitions, + }; + } + } catch (e) { + debug('Failed to process a workspace', e.message); + } + return yarnWorkspacesMap; +} diff --git a/src/lib/reachable-vulns.ts b/src/lib/reachable-vulns.ts index 37c02aa24cc..8c734b96837 100644 --- a/src/lib/reachable-vulns.ts +++ b/src/lib/reachable-vulns.ts @@ -37,6 +37,7 @@ export async function validatePayload( if ( packageManager && !options.allProjects && + !options.yarnWorkspaces && !REACHABLE_VULNS_SUPPORTED_PACKAGE_MANAGERS.includes(packageManager) ) { throw new FeatureNotSupportedByPackageManagerError( diff --git a/src/lib/snyk-test/index.js b/src/lib/snyk-test/index.js index b0b52971616..a6393daf88c 100644 --- a/src/lib/snyk-test/index.js +++ b/src/lib/snyk-test/index.js @@ -32,11 +32,9 @@ async function test(root, options, callback) { function executeTest(root, options) { try { if (!options.allProjects) { - if (options.iac) { - options.packageManager = detect.isIacProject(root, options); - } else { - options.packageManager = detect.detectPackageManager(root, options); - } + options.packageManager = options.iac + ? detect.isIacProject(root, options) + : detect.detectPackageManager(root, options); } return run(root, options).then((results) => { for (const res of results) { @@ -70,6 +68,7 @@ function run(root, options) { !( options.docker || options.allProjects || + options.yarnWorkspaces || pm.SUPPORTED_PACKAGE_MANAGER_NAME[packageManager] ) ) { diff --git a/src/lib/snyk-test/run-test.ts b/src/lib/snyk-test/run-test.ts index cea2a91f1dc..aa814c5da05 100644 --- a/src/lib/snyk-test/run-test.ts +++ b/src/lib/snyk-test/run-test.ts @@ -190,10 +190,10 @@ async function parseRes( pkgManager, options.severityThreshold, ); - // For Node.js: inject additional information (for remediation etc.) into the response. if (payload.modules) { - res.dependencyCount = payload.modules.numDependencies; + res.dependencyCount = + payload.modules.numDependencies || depGraph.getPkgs().length - 1; if (res.vulnerabilities) { res.vulnerabilities.forEach((vuln) => { if (payload.modules && payload.modules.pluck) { diff --git a/src/lib/types.ts b/src/lib/types.ts index 902f2b700b4..8c01fd956ec 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -19,6 +19,7 @@ export interface TestOptions { showVulnPaths: ShowVulnPaths; failOn?: FailOn; reachableVulns?: boolean; + yarnWorkspaces?: boolean; } export interface WizardOptions { @@ -63,6 +64,7 @@ export interface Options { allProjects?: boolean; detectionDepth?: number; exclude?: string; + strictOutOfSync?: boolean; // Used with the Docker plugin only. Allows requesting some experimental/unofficial features. experimental?: boolean; } @@ -85,6 +87,7 @@ export interface MonitorOptions { // Used with the Docker plugin only. Allows requesting some experimental/unofficial features. experimental?: boolean; reachableVulns?: boolean; + yarnWorkspaces?: boolean; } export interface MonitorMeta { diff --git a/test/acceptance/cli-args.test.ts b/test/acceptance/cli-args.test.ts index 7ed01400152..f637226d83d 100644 --- a/test/acceptance/cli-args.test.ts +++ b/test/acceptance/cli-args.test.ts @@ -120,6 +120,7 @@ const argsNotAllowedWithAllProjects = [ 'project-name', 'docker', 'all-sub-projects', + 'yarn-workspaces', ]; argsNotAllowedWithAllProjects.forEach((arg) => { diff --git a/test/acceptance/cli-test/cli-test.yarn-workspaces.spec.ts b/test/acceptance/cli-test/cli-test.yarn-workspaces.spec.ts new file mode 100644 index 00000000000..81a4e5982b1 --- /dev/null +++ b/test/acceptance/cli-test/cli-test.yarn-workspaces.spec.ts @@ -0,0 +1,93 @@ +import { AcceptanceTests } from './cli-test.acceptance.test'; + +export const YarnTests: AcceptanceTests = { + language: 'Yarn', + tests: { + // yarn lockfile based testing is only supported for node 4+ + '`test yarn-workspaces-out-of-sync --yarn-workspaces` out of sync fails': ( + params, + utils, + ) => async (t) => { + utils.chdirWorkspaces(); + try { + await params.cli.test('yarn-out-of-sync', { dev: true }); + t.fail('Should fail'); + } catch (e) { + t.equal( + e.message, + '\nTesting yarn-out-of-sync...\n\n' + + 'Dependency snyk was not found in yarn.lock.' + + ' Your package.json and yarn.lock are probably out of sync.' + + ' Please run "yarn install" and try again.', + 'Contains enough info about err', + ); + } + }, + '`test yarn-workspaces-workspace-out-of-sync --yarn-workspaces --strict-out-of-sync=false` passes': ( + params, + utils, + ) => async (t) => { + utils.chdirWorkspaces(); + await params.cli.test('yarn-workspaces-out-of-sync', { + dev: true, + strictOutOfSync: false, + }); + const req = params.server.popRequest(); + t.match(req.url, '/test-dep-graph', 'posts to correct url'); + const depGraph = req.body.depGraph; + t.same( + depGraph.pkgs.map((p) => p.id).sort(), + [ + // TODO: add packages + ].sort(), + 'depGraph looks fine', + ); + }, + + '`test yarn-workspace --yarn-workspaces --dev` sends pkg info': ( + params, + utils, + ) => async (t) => { + utils.chdirWorkspaces(); + await params.cli.test('yarn-workspace', { + yanrWorkspaces: true, + dev: true, + }); + const req = params.server.popRequest(); + t.match(req.url, '/test-dep-graph', 'posts to correct url'); + t.match(req.body.targetFile, undefined, 'target is undefined'); + const depGraph = req.body.depGraph; + t.same( + depGraph.pkgs.map((p) => p.id).sort(), + [ + // TODO: add packages + ].sort(), + 'depGraph looks fine', + ); + }, + '`test` on a yarn workspace does work and displays appropriate text': ( + params, + utils, + ) => async (t) => { + utils.chdirWorkspaces('yarn-workspace'); + await params.cli.test(); + const req = params.server.popRequest(); + t.equal(req.method, 'POST', 'makes POST request'); + t.equal( + req.headers['x-snyk-cli-version'], + params.versionNumber, + 'sends version number', + ); + t.match(req.url, '/test-dep-graph', 'posts to correct url'); + t.match(req.body.targetFile, undefined, 'target is undefined'); + const depGraph = req.body.depGraph; + t.same( + depGraph.pkgs.map((p) => p.id).sort(), + [ + // TODO: add packages + ].sort(), + 'depGraph looks fine', + ); + }, + }, +}; diff --git a/test/acceptance/workspaces/yarn-workspaces/package.json b/test/acceptance/workspaces/yarn-workspaces/package.json new file mode 100644 index 00000000000..a5e8eac850c --- /dev/null +++ b/test/acceptance/workspaces/yarn-workspaces/package.json @@ -0,0 +1,19 @@ +{ + "private": true, + "workspaces": [ + "packages/*" + ], + "resolutions": { + "node-fetch": "^2.3.0" + }, + "engines": { + "node": "^8.11.1 || ^10.11.0", + "yarn": "1.10.1" + }, + "devDependencies": { + "wsrun": "^3.6.2" + }, + "dependencies": { + "node-fetch": "^2.3.0" + } +} diff --git a/test/acceptance/workspaces/yarn-workspaces/packages/apples/package.json b/test/acceptance/workspaces/yarn-workspaces/packages/apples/package.json new file mode 100644 index 00000000000..0c517e52e05 --- /dev/null +++ b/test/acceptance/workspaces/yarn-workspaces/packages/apples/package.json @@ -0,0 +1,20 @@ +{ + "name": "apples", + "version": "1.0.0", + "license": "UNLICENSED", + "main": "./src/index.js", + "scripts": { + "precommit": "lint-staged" + }, + "jest": { + "preset": "@lego-shop/lego-scripts" + }, + "babel": { + "presets": [ + "@lego-shop/lego-scripts/babel" + ] + }, + "dependencies": { + "debug": "^2.7.2" + } +} diff --git a/test/acceptance/workspaces/yarn-workspaces/packages/tomatoes/package.json b/test/acceptance/workspaces/yarn-workspaces/packages/tomatoes/package.json new file mode 100644 index 00000000000..a5dddde28eb --- /dev/null +++ b/test/acceptance/workspaces/yarn-workspaces/packages/tomatoes/package.json @@ -0,0 +1,10 @@ +{ + "name": "tomatoes", + "version": "1.0.0", + "license": "UNLICENSED", + "main": "./src/index.js", + "dependencies": { + "object-assign": "4.1.1", + "node-fetch": "2.2.0" + } +} diff --git a/test/acceptance/workspaces/yarn-workspaces/yarn.lock b/test/acceptance/workspaces/yarn-workspaces/yarn.lock new file mode 100644 index 00000000000..9111d3f0e77 --- /dev/null +++ b/test/acceptance/workspaces/yarn-workspaces/yarn.lock @@ -0,0 +1,501 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +bluebird@^3.5.1: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= + +chalk@^2.3.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +debug@^2.7.2: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +decamelize@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +glob@^7.1.2: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= + dependencies: + invert-kv "^1.0.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +lodash@^4.17.4: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= + dependencies: + mimic-fn "^1.0.0" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +node-fetch@2.2.0, node-fetch@^2.3.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" + integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +object-assign@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +signal-exit@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + +split@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" + integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== + dependencies: + through "2" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +throat@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" + integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= + +through@2: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +wsrun@^3.6.2: + version "3.6.6" + resolved "https://registry.yarnpkg.com/wsrun/-/wsrun-3.6.6.tgz#b4a9235f175fb4a8e0e3747fc0e09d093fa84d9c" + integrity sha512-XGSx5bNjdLNUF8wMg6R3FZ5H07Rj46DW7LU6fCuf75V75STIm6vyb/f1wXVc5wK8BSHBDqmrZAzxMgOegI3Opw== + dependencies: + bluebird "^3.5.1" + chalk "^2.3.0" + glob "^7.1.2" + lodash "^4.17.4" + minimatch "^3.0.4" + split "^1.0.1" + throat "^4.1.0" + yargs "^10.0.3" + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yargs-parser@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" + integrity sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ== + dependencies: + camelcase "^4.1.0" + +yargs@^10.0.3: + version "10.1.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5" + integrity sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig== + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^8.1.0" From d942b3c5912818df8f3627a31d202821ebadad85 Mon Sep 17 00:00:00 2001 From: ghe Date: Tue, 16 Jun 2020 08:50:43 +0100 Subject: [PATCH 2/9] test: yarn workspaces tests & fixtures --- .../nodejs-plugin/yarn-workspaces-parser.ts | 36 +- src/lib/snyk-test/run-test.ts | 4 +- .../cli-test/cli-test.acceptance.test.ts | 2 + .../cli-test/cli-test.yarn-workspaces.spec.ts | 185 +++++-- .../yarn-workspace-out-of-sync/package.json | 20 + .../packages/apples/package.json | 13 + .../packages/tomatoes/package.json | 10 + .../yarn-workspace-out-of-sync/yarn.lock | 501 ++++++++++++++++++ .../workspaces/yarn-workspaces/.snyk | 9 + .../yarn-workspaces/packages/apples/.snyk | 13 + .../packages/apples/package.json | 10 +- .../workspaces/yarn-workspaces/yarn.lock | 91 +--- 12 files changed, 740 insertions(+), 154 deletions(-) create mode 100644 test/acceptance/workspaces/yarn-workspace-out-of-sync/package.json create mode 100644 test/acceptance/workspaces/yarn-workspace-out-of-sync/packages/apples/package.json create mode 100644 test/acceptance/workspaces/yarn-workspace-out-of-sync/packages/tomatoes/package.json create mode 100644 test/acceptance/workspaces/yarn-workspace-out-of-sync/yarn.lock create mode 100644 test/acceptance/workspaces/yarn-workspaces/.snyk create mode 100644 test/acceptance/workspaces/yarn-workspaces/packages/apples/.snyk diff --git a/src/lib/plugins/nodejs-plugin/yarn-workspaces-parser.ts b/src/lib/plugins/nodejs-plugin/yarn-workspaces-parser.ts index 5ca47e3d9a2..9710d07945c 100644 --- a/src/lib/plugins/nodejs-plugin/yarn-workspaces-parser.ts +++ b/src/lib/plugins/nodejs-plugin/yarn-workspaces-parser.ts @@ -1,5 +1,8 @@ import * as baseDebug from 'debug'; -const debug = baseDebug('yarn-workspaces'); +import * as pathUtil from 'path'; +import * as _ from 'lodash'; + +const debug = baseDebug('snyk:yarn-workspaces'); import * as fs from 'fs'; import * as lockFileParser from 'snyk-nodejs-lockfile-parser'; import * as path from 'path'; @@ -17,9 +20,23 @@ export async function processYarnWorkspaces( }, targetFiles: string[], ): Promise { - const yarnTargetFiles = targetFiles.filter((f) => f.endsWith('package.json')); + // the order of folders is important + // must have the root level most folders at the top + const yarnTargetFiles: { + [dir: string]: Array<{ + path: string; + base: string; + dir: string; + }>; + } = _(targetFiles) + .map((p) => ({ path: p, ...pathUtil.parse(p) })) + .filter((res) => ['package.json'].includes(res.base)) + .sortBy('dir') + .groupBy('dir') + .value(); + debug(`processing Yarn workspaces (${targetFiles.length})`); - if (yarnTargetFiles.length === 0) { + if (Object.keys(yarnTargetFiles).length === 0) { throw NoSupportedManifestsFoundError([root]); } let yarnWorkspacesMap = {}; @@ -32,19 +49,20 @@ export async function processYarnWorkspaces( }, scannedProjects: [], }; - for (const packageJsonFileName of yarnTargetFiles) { + // the folders must be ordered highest first + for (const directory of Object.keys(yarnTargetFiles)) { + const packageJsonFileName = pathUtil.join(directory, 'package.json'); const packageJson = getFileContents(root, packageJsonFileName); yarnWorkspacesMap = { ...yarnWorkspacesMap, ...getWorkspacesMap(packageJson), }; - for (const workspaceRoot of Object.keys(yarnWorkspacesMap)) { const workspaces = yarnWorkspacesMap[workspaceRoot].workspaces || []; const match = workspaces - .map((pattern) => - packageJsonFileName.includes(pattern.replace(/\*/, '')), - ) + .map((pattern) => { + return packageJsonFileName.includes(pattern.replace(/\*/, '')); + }) .filter(Boolean); if (match) { @@ -71,7 +89,7 @@ export async function processYarnWorkspaces( ); const project: ScannedProjectCustom = { packageManager: 'yarn', - targetFile: path.parse(packageJson.name).base, + targetFile: path.relative(root, packageJson.name), depTree: res as any, plugin: { name: 'snyk-nodejs-lockfile-parser', diff --git a/src/lib/snyk-test/run-test.ts b/src/lib/snyk-test/run-test.ts index aa814c5da05..cea2a91f1dc 100644 --- a/src/lib/snyk-test/run-test.ts +++ b/src/lib/snyk-test/run-test.ts @@ -190,10 +190,10 @@ async function parseRes( pkgManager, options.severityThreshold, ); + // For Node.js: inject additional information (for remediation etc.) into the response. if (payload.modules) { - res.dependencyCount = - payload.modules.numDependencies || depGraph.getPkgs().length - 1; + res.dependencyCount = payload.modules.numDependencies; if (res.vulnerabilities) { res.vulnerabilities.forEach((vuln) => { if (payload.modules && payload.modules.pluck) { diff --git a/test/acceptance/cli-test/cli-test.acceptance.test.ts b/test/acceptance/cli-test/cli-test.acceptance.test.ts index e854772dca6..92655fd2c0a 100644 --- a/test/acceptance/cli-test/cli-test.acceptance.test.ts +++ b/test/acceptance/cli-test/cli-test.acceptance.test.ts @@ -26,6 +26,7 @@ import { RubyTests } from './cli-test.ruby.spec'; import { SbtTests } from './cli-test.sbt.spec'; import { YarnTests } from './cli-test.yarn.spec'; import { IacK8sTests } from './cli-test.iac-k8s.spec'; +import { YarnWorkspacesTests } from './cli-test.yarn-workspaces.spec'; import { AllProjectsTests } from './cli-test.all-projects.spec'; const languageTests: AcceptanceTests[] = [ @@ -42,6 +43,7 @@ const languageTests: AcceptanceTests[] = [ SbtTests, YarnTests, IacK8sTests, + YarnWorkspacesTests, ]; const { test, only } = tap; diff --git a/test/acceptance/cli-test/cli-test.yarn-workspaces.spec.ts b/test/acceptance/cli-test/cli-test.yarn-workspaces.spec.ts index 81a4e5982b1..1e08b3faadb 100644 --- a/test/acceptance/cli-test/cli-test.yarn-workspaces.spec.ts +++ b/test/acceptance/cli-test/cli-test.yarn-workspaces.spec.ts @@ -1,21 +1,27 @@ +import * as sinon from 'sinon'; + import { AcceptanceTests } from './cli-test.acceptance.test'; -export const YarnTests: AcceptanceTests = { +export const YarnWorkspacesTests: AcceptanceTests = { language: 'Yarn', tests: { // yarn lockfile based testing is only supported for node 4+ - '`test yarn-workspaces-out-of-sync --yarn-workspaces` out of sync fails': ( + '`test yarn-workspace-out-of-sync --yarn-workspaces` out of sync fails': ( params, utils, ) => async (t) => { utils.chdirWorkspaces(); try { - await params.cli.test('yarn-out-of-sync', { dev: true }); + await params.cli.test('yarn-workspace-out-of-sync', { + dev: true, + yarnWorkspaces: true, + detectionDepth: 3, + }); t.fail('Should fail'); } catch (e) { t.equal( e.message, - '\nTesting yarn-out-of-sync...\n\n' + + '\nTesting yarn-workspace-out-of-sync...\n\n' + 'Dependency snyk was not found in yarn.lock.' + ' Your package.json and yarn.lock are probably out of sync.' + ' Please run "yarn install" and try again.', @@ -23,12 +29,12 @@ export const YarnTests: AcceptanceTests = { ); } }, - '`test yarn-workspaces-workspace-out-of-sync --yarn-workspaces --strict-out-of-sync=false` passes': ( + '`test yarn-workspace-out-of-sync --yarn-workspaces --strict-out-of-sync=false --dev` passes': ( params, utils, ) => async (t) => { utils.chdirWorkspaces(); - await params.cli.test('yarn-workspaces-out-of-sync', { + await params.cli.test('yarn-workspace-out-of-sync', { dev: true, strictOutOfSync: false, }); @@ -38,56 +44,141 @@ export const YarnTests: AcceptanceTests = { t.same( depGraph.pkgs.map((p) => p.id).sort(), [ - // TODO: add packages + 'ansi-regex@2.1.1', + 'ansi-regex@3.0.0', + 'ansi-styles@3.2.1', + 'balanced-match@1.0.0', + 'bluebird@3.7.2', + 'brace-expansion@1.1.11', + 'camelcase@4.1.0', + 'chalk@2.4.2', + 'cliui@4.1.0', + 'code-point-at@1.1.0', + 'color-convert@1.9.3', + 'color-name@1.1.3', + 'concat-map@0.0.1', + 'cross-spawn@5.1.0', + 'decamelize@1.2.0', + 'escape-string-regexp@1.0.5', + 'execa@0.7.0', + 'find-up@2.1.0', + 'fs.realpath@1.0.0', + 'get-caller-file@1.0.3', + 'get-stream@3.0.0', + 'glob@7.1.6', + 'has-flag@3.0.0', + 'inflight@1.0.6', + 'inherits@2.0.4', + 'invert-kv@1.0.0', + 'is-fullwidth-code-point@1.0.0', + 'is-fullwidth-code-point@2.0.0', + 'is-stream@1.1.0', + 'isexe@2.0.0', + 'lcid@1.0.0', + 'locate-path@2.0.0', + 'lodash@4.17.15', + 'lru-cache@4.1.5', + 'mem@1.1.0', + 'mimic-fn@1.2.0', + 'minimatch@3.0.4', + 'node-fetch@2.6.0', + 'npm-run-path@2.0.2', + 'number-is-nan@1.0.1', + 'once@1.4.0', + 'os-locale@2.1.0', + 'p-finally@1.0.0', + 'p-limit@1.3.0', + 'p-locate@2.0.0', + 'p-try@1.0.0', + 'package.json@', + 'path-exists@3.0.0', + 'path-is-absolute@1.0.1', + 'path-key@2.0.1', + 'pseudomap@1.0.2', + 'require-directory@2.1.1', + 'require-main-filename@1.0.1', + 'set-blocking@2.0.0', + 'shebang-command@1.2.0', + 'shebang-regex@1.0.0', + 'signal-exit@3.0.3', + 'snyk@1.320.0', + 'split@1.0.1', + 'string-width@1.0.2', + 'string-width@2.1.1', + 'strip-ansi@3.0.1', + 'strip-ansi@4.0.0', + 'strip-eof@1.0.0', + 'supports-color@5.5.0', + 'throat@4.1.0', + 'through@2.3.8', + 'which-module@2.0.0', + 'which@1.3.1', + 'wrap-ansi@2.1.0', + 'wrappy@1.0.2', + 'wsrun@3.6.6', + 'y18n@3.2.1', + 'yallist@2.1.2', + 'yargs-parser@8.1.0', + 'yargs@10.1.2', ].sort(), 'depGraph looks fine', ); }, - - '`test yarn-workspace --yarn-workspaces --dev` sends pkg info': ( - params, - utils, - ) => async (t) => { + 'test --yarn-workspaces --detection-depth=5': (params, utils) => async ( + t, + ) => { utils.chdirWorkspaces(); - await params.cli.test('yarn-workspace', { - yanrWorkspaces: true, - dev: true, + const result = await params.cli.test('yarn-workspaces', { + yarnWorkspaces: true, + detectionDepth: 5, }); - const req = params.server.popRequest(); - t.match(req.url, '/test-dep-graph', 'posts to correct url'); - t.match(req.body.targetFile, undefined, 'target is undefined'); - const depGraph = req.body.depGraph; - t.same( - depGraph.pkgs.map((p) => p.id).sort(), - [ - // TODO: add packages - ].sort(), - 'depGraph looks fine', + const loadPlugin = sinon.spy(params.plugins, 'loadPlugin'); + // the parser is used directly + t.ok(loadPlugin.withArgs('yarn').notCalled, 'skips load plugin'); + t.match(result.getDisplayResults(), 'Package manager: yarn\n'); + t.match( + result.getDisplayResults(), + 'Project name: package.json', + 'yarn project in output', ); - }, - '`test` on a yarn workspace does work and displays appropriate text': ( - params, - utils, - ) => async (t) => { - utils.chdirWorkspaces('yarn-workspace'); - await params.cli.test(); - const req = params.server.popRequest(); - t.equal(req.method, 'POST', 'makes POST request'); - t.equal( - req.headers['x-snyk-cli-version'], - params.versionNumber, - 'sends version number', + t.match( + result.getDisplayResults(), + 'Project name: tomatoes', + 'yarn project in output', ); - t.match(req.url, '/test-dep-graph', 'posts to correct url'); - t.match(req.body.targetFile, undefined, 'target is undefined'); - const depGraph = req.body.depGraph; - t.same( - depGraph.pkgs.map((p) => p.id).sort(), - [ - // TODO: add packages - ].sort(), - 'depGraph looks fine', + t.match( + result.getDisplayResults(), + 'Project name: apples', + 'yarn project in output', + ); + t.match( + result.getDisplayResults(), + 'Tested 3 projects, no vulnerable paths were found.', + 'no vulnerable paths found as both policies detected and applied.', ); + + params.server.popRequests(3).forEach((req) => { + t.equal(req.method, 'POST', 'makes POST request'); + t.equal( + req.headers['x-snyk-cli-version'], + params.versionNumber, + 'sends version number', + ); + t.match(req.url, '/api/v1/test-dep-graph', 'posts to correct url'); + t.ok(req.body.depGraph, 'body contains depGraph'); + t.ok(req.body.policy, 'body contains policy'); + t.equal( + req.body.policyLocations, + ['yarn-workspaces', 'yarn-workspaces/apples'], + 'policy locations', + ); + + t.equal( + req.body.depGraph.pkgManager.name, + 'yarn', + 'depGraph has package manager', + ); + }); }, }, }; diff --git a/test/acceptance/workspaces/yarn-workspace-out-of-sync/package.json b/test/acceptance/workspaces/yarn-workspace-out-of-sync/package.json new file mode 100644 index 00000000000..1af6c984761 --- /dev/null +++ b/test/acceptance/workspaces/yarn-workspace-out-of-sync/package.json @@ -0,0 +1,20 @@ +{ + "private": true, + "workspaces": [ + "packages/*" + ], + "resolutions": { + "node-fetch": "^2.3.0" + }, + "engines": { + "node": "^8.11.1 || ^10.11.0", + "yarn": "1.10.1" + }, + "devDependencies": { + "wsrun": "^3.6.2" + }, + "dependencies": { + "node-fetch": "^2.3.0", + "snyk": "1.320.0" + } +} diff --git a/test/acceptance/workspaces/yarn-workspace-out-of-sync/packages/apples/package.json b/test/acceptance/workspaces/yarn-workspace-out-of-sync/packages/apples/package.json new file mode 100644 index 00000000000..bf49c4a1604 --- /dev/null +++ b/test/acceptance/workspaces/yarn-workspace-out-of-sync/packages/apples/package.json @@ -0,0 +1,13 @@ +{ + "name": "apples", + "version": "1.0.0", + "license": "UNLICENSED", + "main": "./src/index.js", + "scripts": { + "precommit": "lint-staged" + }, + "dependencies": { + "debug": "^2.7.2", + "object-assign": "4.1.1" + } +} diff --git a/test/acceptance/workspaces/yarn-workspace-out-of-sync/packages/tomatoes/package.json b/test/acceptance/workspaces/yarn-workspace-out-of-sync/packages/tomatoes/package.json new file mode 100644 index 00000000000..a5dddde28eb --- /dev/null +++ b/test/acceptance/workspaces/yarn-workspace-out-of-sync/packages/tomatoes/package.json @@ -0,0 +1,10 @@ +{ + "name": "tomatoes", + "version": "1.0.0", + "license": "UNLICENSED", + "main": "./src/index.js", + "dependencies": { + "object-assign": "4.1.1", + "node-fetch": "2.2.0" + } +} diff --git a/test/acceptance/workspaces/yarn-workspace-out-of-sync/yarn.lock b/test/acceptance/workspaces/yarn-workspace-out-of-sync/yarn.lock new file mode 100644 index 00000000000..9111d3f0e77 --- /dev/null +++ b/test/acceptance/workspaces/yarn-workspace-out-of-sync/yarn.lock @@ -0,0 +1,501 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +bluebird@^3.5.1: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= + +chalk@^2.3.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +debug@^2.7.2: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +decamelize@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +glob@^7.1.2: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= + dependencies: + invert-kv "^1.0.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +lodash@^4.17.4: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= + dependencies: + mimic-fn "^1.0.0" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +node-fetch@2.2.0, node-fetch@^2.3.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" + integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +object-assign@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +signal-exit@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + +split@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" + integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== + dependencies: + through "2" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +throat@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" + integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= + +through@2: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +wsrun@^3.6.2: + version "3.6.6" + resolved "https://registry.yarnpkg.com/wsrun/-/wsrun-3.6.6.tgz#b4a9235f175fb4a8e0e3747fc0e09d093fa84d9c" + integrity sha512-XGSx5bNjdLNUF8wMg6R3FZ5H07Rj46DW7LU6fCuf75V75STIm6vyb/f1wXVc5wK8BSHBDqmrZAzxMgOegI3Opw== + dependencies: + bluebird "^3.5.1" + chalk "^2.3.0" + glob "^7.1.2" + lodash "^4.17.4" + minimatch "^3.0.4" + split "^1.0.1" + throat "^4.1.0" + yargs "^10.0.3" + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yargs-parser@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" + integrity sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ== + dependencies: + camelcase "^4.1.0" + +yargs@^10.0.3: + version "10.1.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5" + integrity sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig== + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^8.1.0" diff --git a/test/acceptance/workspaces/yarn-workspaces/.snyk b/test/acceptance/workspaces/yarn-workspaces/.snyk new file mode 100644 index 00000000000..8d9d21960e5 --- /dev/null +++ b/test/acceptance/workspaces/yarn-workspaces/.snyk @@ -0,0 +1,9 @@ +# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. +version: v1.14.1 +# ignores vulnerabilities until expiry date; change duration by modifying expiry date +ignore: + 'npm:node-uuid:20111130': + - '*': + reason: None Given + expires: 2020-07-17T21:40:21.917Z +patch: {} diff --git a/test/acceptance/workspaces/yarn-workspaces/packages/apples/.snyk b/test/acceptance/workspaces/yarn-workspaces/packages/apples/.snyk new file mode 100644 index 00000000000..3bcecb61bb6 --- /dev/null +++ b/test/acceptance/workspaces/yarn-workspaces/packages/apples/.snyk @@ -0,0 +1,13 @@ +# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. +version: v1.14.1 +# ignores vulnerabilities until expiry date; change duration by modifying expiry date +ignore: + 'npm:node-uuid:20160328': + - '*': + reason: None Given + expires: 2020-07-17T17:21:53.744Z + 'npm:node-uuid:20111130': + - '*': + reason: None Given + expires: 2020-07-17T21:40:21.917Z +patch: {} diff --git a/test/acceptance/workspaces/yarn-workspaces/packages/apples/package.json b/test/acceptance/workspaces/yarn-workspaces/packages/apples/package.json index 0c517e52e05..58ecc3f395f 100644 --- a/test/acceptance/workspaces/yarn-workspaces/packages/apples/package.json +++ b/test/acceptance/workspaces/yarn-workspaces/packages/apples/package.json @@ -6,15 +6,7 @@ "scripts": { "precommit": "lint-staged" }, - "jest": { - "preset": "@lego-shop/lego-scripts" - }, - "babel": { - "presets": [ - "@lego-shop/lego-scripts/babel" - ] - }, "dependencies": { - "debug": "^2.7.2" + "node-uuid": "1.3.0" } } diff --git a/test/acceptance/workspaces/yarn-workspaces/yarn.lock b/test/acceptance/workspaces/yarn-workspaces/yarn.lock index 9111d3f0e77..66f15253a94 100644 --- a/test/acceptance/workspaces/yarn-workspaces/yarn.lock +++ b/test/acceptance/workspaces/yarn-workspaces/yarn.lock @@ -5,34 +5,28 @@ ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= bluebird@^3.5.1: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" @@ -40,12 +34,10 @@ brace-expansion@^1.1.7: camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" - integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= chalk@^2.3.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" @@ -54,7 +46,6 @@ chalk@^2.3.0: cliui@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" - integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== dependencies: string-width "^2.1.1" strip-ansi "^4.0.0" @@ -63,55 +54,40 @@ cliui@^4.0.0: code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= dependencies: lru-cache "^4.0.1" shebang-command "^1.2.0" which "^1.2.9" -debug@^2.7.2: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= execa@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" - integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= dependencies: cross-spawn "^5.0.1" get-stream "^3.0.0" @@ -124,29 +100,24 @@ execa@^0.7.0: find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= dependencies: locate-path "^2.0.0" fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= get-caller-file@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= glob@^7.1.2: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -158,12 +129,10 @@ glob@^7.1.2: has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= dependencies: once "^1.3.0" wrappy "1" @@ -171,46 +140,38 @@ inflight@^1.0.4: inherits@2: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= lcid@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= dependencies: invert-kv "^1.0.0" locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= dependencies: p-locate "^2.0.0" path-exists "^3.0.0" @@ -218,12 +179,10 @@ locate-path@^2.0.0: lodash@^4.17.4: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== lru-cache@^4.0.1: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== dependencies: pseudomap "^1.0.2" yallist "^2.1.2" @@ -231,60 +190,50 @@ lru-cache@^4.0.1: mem@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" - integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= dependencies: mimic-fn "^1.0.0" mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" -ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - node-fetch@2.2.0, node-fetch@^2.3.0: version "2.6.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" - integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== + +node-uuid@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.3.0.tgz#ae7aaa86c2941a2ce3af4d07de4e636f7039a051" npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= dependencies: path-key "^2.0.0" number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= object-assign@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" os-locale@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" - integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== dependencies: execa "^0.7.0" lcid "^1.0.0" @@ -293,90 +242,74 @@ os-locale@^2.0.0: p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== dependencies: p-try "^1.0.0" p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= dependencies: p-limit "^1.1.0" p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= path-key@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= dependencies: shebang-regex "^1.0.0" shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= signal-exit@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== split@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" - integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== dependencies: through "2" string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" @@ -385,7 +318,6 @@ string-width@^1.0.1: string-width@^2.0.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" @@ -393,55 +325,46 @@ string-width@^2.0.0, string-width@^2.1.1: strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= dependencies: ansi-regex "^2.0.0" strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= dependencies: ansi-regex "^3.0.0" strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" throat@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" - integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= through@2: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" @@ -449,12 +372,10 @@ wrap-ansi@^2.0.0: wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= wsrun@^3.6.2: version "3.6.6" resolved "https://registry.yarnpkg.com/wsrun/-/wsrun-3.6.6.tgz#b4a9235f175fb4a8e0e3747fc0e09d093fa84d9c" - integrity sha512-XGSx5bNjdLNUF8wMg6R3FZ5H07Rj46DW7LU6fCuf75V75STIm6vyb/f1wXVc5wK8BSHBDqmrZAzxMgOegI3Opw== dependencies: bluebird "^3.5.1" chalk "^2.3.0" @@ -468,24 +389,20 @@ wsrun@^3.6.2: y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= yargs-parser@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" - integrity sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ== dependencies: camelcase "^4.1.0" yargs@^10.0.3: version "10.1.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5" - integrity sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig== dependencies: cliui "^4.0.0" decamelize "^1.1.1" From 1168d094685f5a130ac170cd3bf48c5a42c596be Mon Sep 17 00:00:00 2001 From: ghe Date: Fri, 19 Jun 2020 16:35:08 +0100 Subject: [PATCH 3/9] feat: throw if using workspaces with disallowed options --- src/cli/index.ts | 30 ++++++++++++++++++++++++++++ test/acceptance/cli-args.test.ts | 34 ++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/src/cli/index.ts b/src/cli/index.ts index 79a800949a4..75d382b802c 100755 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -241,24 +241,54 @@ async function main() { 'all-projects', ]); } + + if (args.options['project-name'] && args.options.yarnWorkspaces) { + throw new UnsupportedOptionCombinationError([ + 'project-name', + 'yarn-workspaces', + ]); + } + + if (args.options.file && args.options.yarnWorkspaces) { + throw new UnsupportedOptionCombinationError(['file', 'all-projects']); + } + if (args.options.file && args.options.allProjects) { throw new UnsupportedOptionCombinationError(['file', 'all-projects']); } + if (args.options.yarnWorkspaces && args.options.allProjects) { throw new UnsupportedOptionCombinationError([ 'yarn-workspaces', 'all-projects', ]); } + + if (args.options.packageManager && args.options.yarnWorkspaces) { + throw new UnsupportedOptionCombinationError([ + 'package-manager', + 'yarn-workspaces', + ]); + } + if (args.options.packageManager && args.options.allProjects) { throw new UnsupportedOptionCombinationError([ 'package-manager', 'all-projects', ]); } + if (args.options.docker && args.options.allProjects) { throw new UnsupportedOptionCombinationError(['docker', 'all-projects']); } + + if (args.options.allSubProjects && args.options.yarnWorkspaces) { + throw new UnsupportedOptionCombinationError([ + 'all-sub-projects', + 'yarn-workspaces', + ]); + } + if (args.options.allSubProjects && args.options.allProjects) { throw new UnsupportedOptionCombinationError([ 'all-sub-projects', diff --git a/test/acceptance/cli-args.test.ts b/test/acceptance/cli-args.test.ts index f637226d83d..23781bdf71a 100644 --- a/test/acceptance/cli-args.test.ts +++ b/test/acceptance/cli-args.test.ts @@ -114,6 +114,40 @@ test('`test --file=blah --scan-all-unmanaged`', (t) => { }); }); +const argsNotAllowedWithYarnWorkspaces = [ + 'file', + 'package-manager', + 'project-name', + 'docker', + 'all-sub-projects', + 'all-projects', +]; + +argsNotAllowedWithYarnWorkspaces.forEach((arg) => { + test(`using --${arg} and --yarn-workspaces displays error message`, (t) => { + t.plan(2); + exec(`node ${main} test --${arg} --yarn-workspaces`, (err, stdout) => { + if (err) { + throw err; + } + t.match( + stdout.trim(), + `The following option combination is not currently supported: ${arg} + all-projects`, + 'when using test', + ); + }); + exec(`node ${main} monitor --${arg} --yarn-workspaces`, (err, stdout) => { + if (err) { + throw err; + } + t.match( + stdout.trim(), + `The following option combination is not currently supported: ${arg} + all-projects`, + 'when using monitor', + ); + }); + }); +}); const argsNotAllowedWithAllProjects = [ 'file', 'package-manager', From a88c6c60a9ee44bf2536fec051e9fe0a3890021f Mon Sep 17 00:00:00 2001 From: ghe Date: Tue, 23 Jun 2020 12:41:22 +0100 Subject: [PATCH 4/9] fix: count pkgs from graph if count is undefined --- src/cli/index.ts | 9 +- src/lib/snyk-test/run-test.ts | 4 +- test/acceptance/cli-args.test.ts | 5 +- .../cli-test/cli-test.yarn-workspaces.spec.ts | 124 +++++++++++++++++- 4 files changed, 133 insertions(+), 9 deletions(-) diff --git a/src/cli/index.ts b/src/cli/index.ts index 75d382b802c..87f5b3de5ee 100755 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -250,7 +250,7 @@ async function main() { } if (args.options.file && args.options.yarnWorkspaces) { - throw new UnsupportedOptionCombinationError(['file', 'all-projects']); + throw new UnsupportedOptionCombinationError(['file', 'yarn-workspaces']); } if (args.options.file && args.options.allProjects) { @@ -282,6 +282,13 @@ async function main() { throw new UnsupportedOptionCombinationError(['docker', 'all-projects']); } + if (args.options.docker && args.options.yarnWorkspaces) { + throw new UnsupportedOptionCombinationError([ + 'docker', + 'yarn-workspaces', + ]); + } + if (args.options.allSubProjects && args.options.yarnWorkspaces) { throw new UnsupportedOptionCombinationError([ 'all-sub-projects', diff --git a/src/lib/snyk-test/run-test.ts b/src/lib/snyk-test/run-test.ts index cea2a91f1dc..40810158c9d 100644 --- a/src/lib/snyk-test/run-test.ts +++ b/src/lib/snyk-test/run-test.ts @@ -193,7 +193,9 @@ async function parseRes( // For Node.js: inject additional information (for remediation etc.) into the response. if (payload.modules) { - res.dependencyCount = payload.modules.numDependencies; + res.dependencyCount = + payload.modules.numDependencies || + depGraph.countPathsToRoot(depGraph.rootPkg); if (res.vulnerabilities) { res.vulnerabilities.forEach((vuln) => { if (payload.modules && payload.modules.pluck) { diff --git a/test/acceptance/cli-args.test.ts b/test/acceptance/cli-args.test.ts index 23781bdf71a..5619838a4c2 100644 --- a/test/acceptance/cli-args.test.ts +++ b/test/acceptance/cli-args.test.ts @@ -120,7 +120,6 @@ const argsNotAllowedWithYarnWorkspaces = [ 'project-name', 'docker', 'all-sub-projects', - 'all-projects', ]; argsNotAllowedWithYarnWorkspaces.forEach((arg) => { @@ -132,7 +131,7 @@ argsNotAllowedWithYarnWorkspaces.forEach((arg) => { } t.match( stdout.trim(), - `The following option combination is not currently supported: ${arg} + all-projects`, + `The following option combination is not currently supported: ${arg} + yarn-workspaces`, 'when using test', ); }); @@ -142,7 +141,7 @@ argsNotAllowedWithYarnWorkspaces.forEach((arg) => { } t.match( stdout.trim(), - `The following option combination is not currently supported: ${arg} + all-projects`, + `The following option combination is not currently supported: ${arg} + yarn-workspaces`, 'when using monitor', ); }); diff --git a/test/acceptance/cli-test/cli-test.yarn-workspaces.spec.ts b/test/acceptance/cli-test/cli-test.yarn-workspaces.spec.ts index 1e08b3faadb..4be46eca4c5 100644 --- a/test/acceptance/cli-test/cli-test.yarn-workspaces.spec.ts +++ b/test/acceptance/cli-test/cli-test.yarn-workspaces.spec.ts @@ -135,6 +135,14 @@ export const YarnWorkspacesTests: AcceptanceTests = { const loadPlugin = sinon.spy(params.plugins, 'loadPlugin'); // the parser is used directly t.ok(loadPlugin.withArgs('yarn').notCalled, 'skips load plugin'); + t.teardown(() => { + loadPlugin.restore(); + }); + t.match( + result.getDisplayResults(), + '✓ Tested 1 dependencies for known vulnerabilities, no vulnerable paths found.', + 'correctly showing dep number', + ); t.match(result.getDisplayResults(), 'Package manager: yarn\n'); t.match( result.getDisplayResults(), @@ -156,6 +164,7 @@ export const YarnWorkspacesTests: AcceptanceTests = { 'Tested 3 projects, no vulnerable paths were found.', 'no vulnerable paths found as both policies detected and applied.', ); + let policyCount = 0; params.server.popRequests(3).forEach((req) => { t.equal(req.method, 'POST', 'makes POST request'); @@ -166,19 +175,126 @@ export const YarnWorkspacesTests: AcceptanceTests = { ); t.match(req.url, '/api/v1/test-dep-graph', 'posts to correct url'); t.ok(req.body.depGraph, 'body contains depGraph'); - t.ok(req.body.policy, 'body contains policy'); + + if (req.body.targetFileRelativePath.endsWith('apples/package.json')) { + t.match( + req.body.policy, + 'npm:node-uuid:20160328', + 'policy is as expected', + ); + t.ok(req.body.policy, 'body contains policy'); + policyCount += 1; + } else if ( + req.body.targetFileRelativePath.endsWith('tomatoes/package.json') + ) { + t.notOk(req.body.policy, 'body does not contain policy'); + } else if ( + req.body.targetFileRelativePath.endsWith( + 'yarn-workspaces/package.json', + ) + ) { + t.match( + req.body.policy, + 'npm:node-uuid:20111130', + 'policy is as expected', + ); + t.ok(req.body.policy, 'body contains policy'); + policyCount += 1; + } + t.equal( + req.body.depGraph.pkgManager.name, + 'yarn', + 'depGraph has package manager', + ); + }); + t.equal(policyCount, 2, '2 policies found in a workspace'); + }, + 'test --yarn-workspaces --detection-depth=5 multiple workspaces found': ( + params, + utils, + ) => async (t) => { + utils.chdirWorkspaces(); + const result = await params.cli.test({ + yarnWorkspaces: true, + detectionDepth: 5, + strictOutOfSync: false, + }); + const loadPlugin = sinon.spy(params.plugins, 'loadPlugin'); + // the parser is used directly + t.ok(loadPlugin.withArgs('yarn').notCalled, 'skips load plugin'); + t.teardown(() => { + loadPlugin.restore(); + }); + t.match( + result.getDisplayResults(), + '✓ Tested 1 dependencies for known vulnerabilities, no vulnerable paths found.', + 'correctly showing dep number', + ); + t.match(result.getDisplayResults(), 'Package manager: yarn\n'); + t.match( + result.getDisplayResults(), + 'Project name: package.json', + 'yarn project in output', + ); + t.match( + result.getDisplayResults(), + 'Project name: tomatoes', + 'yarn project in output', + ); + t.match( + result.getDisplayResults(), + 'Project name: apples', + 'yarn project in output', + ); + t.match( + result.getDisplayResults(), + 'Tested 6 projects, no vulnerable paths were found.', + 'Tested 6 projects', + ); + let policyCount = 0; + + params.server.popRequests(3).forEach((req) => { + t.equal(req.method, 'POST', 'makes POST request'); t.equal( - req.body.policyLocations, - ['yarn-workspaces', 'yarn-workspaces/apples'], - 'policy locations', + req.headers['x-snyk-cli-version'], + params.versionNumber, + 'sends version number', ); + t.match(req.url, '/api/v1/test-dep-graph', 'posts to correct url'); + t.ok(req.body.depGraph, 'body contains depGraph'); + if (req.body.targetFileRelativePath.endsWith('apples/package.json')) { + t.match( + req.body.policy, + 'npm:node-uuid:20160328', + 'policy is as expected', + ); + t.ok(req.body.policy, 'body contains policy'); + policyCount += 1; + } else if ( + req.body.targetFileRelativePath.endsWith('tomatoes/package.json') + ) { + t.notOk(req.body.policy, 'body does not contain policy'); + } else if ( + req.body.targetFileRelativePath.endsWith( + 'yarn-workspaces/package.json', + ) + ) { + t.match( + req.body.policy, + 'npm:node-uuid:20111130', + 'policy is as expected', + ); + t.ok(req.body.policy, 'body contains policy'); + policyCount += 1; + } t.equal( req.body.depGraph.pkgManager.name, 'yarn', 'depGraph has package manager', ); }); + t.equal(policyCount, 2, '2 policies found in a workspace'); }, }, }; From 0d9c7e4fd242ecf7657f504361ee2121ae418524 Mon Sep 17 00:00:00 2001 From: ghe Date: Wed, 24 Jun 2020 09:22:53 +0100 Subject: [PATCH 5/9] feat: update help docs with --yarn-workspaces usage --- help/help.txt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/help/help.txt b/help/help.txt index 396b8d9dbd5..f583da86764 100644 --- a/help/help.txt +++ b/help/help.txt @@ -32,19 +32,19 @@ Options: Note gradle is not supported, use --all-sub-projects instead. --detection-depth= (test & monitor commands only) - Use with --all-projects to indicate how many sub-directories to search. + Use with --all-projects or --yarn-workspaces to indicate how many sub-directories to search. Defaults to 2 (the current working directory and one sub-directory). - --exclude= + --exclude= (test & monitor commands only) - Can only be used with --all-projects to indicate sub-directories to exclude. - Directories must be comma seperated. + Can be used with --all-projects and --yarn-workspaces to indicate sub-directories to exclude. + Directories must be comma separated. If using with --detection-depth exclude ignores directories at any level deep. --dev .............. Include devDependencies (defaults to production only). --file= ...... Sets package file. For more help run `snyk help file`. --org= ... Specify the org machine-name to run Snyk with a specific organization. For more help run `snyk help orgs`. --ignore-policy .... Ignores the current policy in .snyk file, org level ignores and project policy on snyk.io. - --trust-policies ... Applies and uses ignore rules from your dependencies's + --trust-policies ... Applies and uses ignore rules from your dependencies' Snyk policies, otherwise ignore policies are only shown as a suggestion. --show-vulnerable-paths= @@ -88,7 +88,7 @@ Options: Maven options: --scan-all-unmanaged - Autodetects maven jars and wars in given directory. + Auto detects maven jars and wars in given directory. Individual testing can be done with --file= Gradle options: @@ -121,6 +121,8 @@ npm options: Yarn options: --strict-out-of-sync= Prevent testing out of sync lockfiles. Defaults to true. + --yarn-workspaces Detect and scan yarn workspaces. Similar to --all-projects you can specify how + many sub-directories to search & exclude some directories. CocoaPods options: --strict-out-of-sync= @@ -153,6 +155,8 @@ Examples: $ snyk monitor --project-name=my-project $ snyk test --docker ubuntu:18.04 --org=my-team $ snyk test --docker app:latest --file=Dockerfile --policy-path=path/to/.snyk + $ snyk test --yarn-workspaces --detection-depth=4 --strict-out-of-sync=false + Possible exit statuses and their meaning: From 9223863658e02651f6dca96c37e1fc3828a671c8 Mon Sep 17 00:00:00 2001 From: ghe Date: Fri, 26 Jun 2020 09:40:12 +0100 Subject: [PATCH 6/9] test: monitor tests for yarn workspaces Escape windows folder paths --- .../cli-monitor.acceptance.test.ts | 49 +++++++++++++++++++ .../cli-test/cli-test.yarn-workspaces.spec.ts | 45 +++++++++++------ 2 files changed, 79 insertions(+), 15 deletions(-) diff --git a/test/acceptance/cli-monitor/cli-monitor.acceptance.test.ts b/test/acceptance/cli-monitor/cli-monitor.acceptance.test.ts index 7d13f7ff11a..f78c4c804e5 100644 --- a/test/acceptance/cli-monitor/cli-monitor.acceptance.test.ts +++ b/test/acceptance/cli-monitor/cli-monitor.acceptance.test.ts @@ -493,6 +493,55 @@ test('`monitor yarn-package with dev dep flag`', async (t) => { t.ok(objectAssign, 'dev dependency'); }); +test('`monitor yarn-workspaces with --yarn-workspaces flag`', async (t) => { + chdirWorkspaces(); + const res = await cli.monitor('yarn-workspaces', { + yarnWorkspaces: true, + detectionDepth: 4, + }); + const req = server.popRequest(); + t.equal(req.method, 'PUT', 'makes PUT request'); + t.equal( + req.headers['x-snyk-cli-version'], + versionNumber, + 'sends version number', + ); + t.match(req.url, '/monitor/yarn/graph', 'puts at correct url'); + t.notOk(req.body.targetFile, 'doesnt send the targetFile'); + t.match(res, 'Monitoring yarn-workspaces (apples)', 'apples workspace found'); + t.match( + res, + 'Monitoring yarn-workspaces (package.json)', + 'root workspace found', + ); + t.match( + res, + 'Monitoring yarn-workspaces (tomatoes)', + 'tomatoes workspace found', + ); +}); + +test('`monitor yarn-workspaces without --yarn-workspaces flag`', async (t) => { + chdirWorkspaces(); + const res = await cli.monitor('yarn-workspaces'); + const req = server.popRequest(); + t.equal(req.method, 'PUT', 'makes PUT request'); + t.equal( + req.headers['x-snyk-cli-version'], + versionNumber, + 'sends version number', + ); + t.match(req.url, '/monitor/yarn/graph', 'puts at correct url'); + t.notOk(req.body.targetFile, 'doesnt send the targetFile'); + t.notOk(res.includes('tomatoes'), 'tomatoes workspace not found'); + t.notOk(res.includes('apples'), 'apples workspace not found'); + t.match( + res, + 'Monitoring yarn-workspaces (package.json)', + 'root workspace found', + ); +}); + test('`monitor ruby-app`', async (t) => { chdirWorkspaces(); await cli.monitor('ruby-app'); diff --git a/test/acceptance/cli-test/cli-test.yarn-workspaces.spec.ts b/test/acceptance/cli-test/cli-test.yarn-workspaces.spec.ts index 4be46eca4c5..7bd3a1105a7 100644 --- a/test/acceptance/cli-test/cli-test.yarn-workspaces.spec.ts +++ b/test/acceptance/cli-test/cli-test.yarn-workspaces.spec.ts @@ -165,6 +165,18 @@ export const YarnWorkspacesTests: AcceptanceTests = { 'no vulnerable paths found as both policies detected and applied.', ); let policyCount = 0; + const applesWorkspace = + process.platform === 'win32' + ? '\\apples\\package.json' + : 'apples/package.json'; + const tomatoesWorkspace = + process.platform === 'win32' + ? '\\tomatoes\\package.json' + : 'tomatoes/package.json'; + const rootWorkspace = + process.platform === 'win32' + ? '\\yarn-workspaces\\package.json' + : 'yarn-workspaces/package.json'; params.server.popRequests(3).forEach((req) => { t.equal(req.method, 'POST', 'makes POST request'); @@ -176,7 +188,7 @@ export const YarnWorkspacesTests: AcceptanceTests = { t.match(req.url, '/api/v1/test-dep-graph', 'posts to correct url'); t.ok(req.body.depGraph, 'body contains depGraph'); - if (req.body.targetFileRelativePath.endsWith('apples/package.json')) { + if (req.body.targetFileRelativePath.endsWith(applesWorkspace)) { t.match( req.body.policy, 'npm:node-uuid:20160328', @@ -185,14 +197,10 @@ export const YarnWorkspacesTests: AcceptanceTests = { t.ok(req.body.policy, 'body contains policy'); policyCount += 1; } else if ( - req.body.targetFileRelativePath.endsWith('tomatoes/package.json') + req.body.targetFileRelativePath.endsWith(tomatoesWorkspace) ) { t.notOk(req.body.policy, 'body does not contain policy'); - } else if ( - req.body.targetFileRelativePath.endsWith( - 'yarn-workspaces/package.json', - ) - ) { + } else if (req.body.targetFileRelativePath.endsWith(rootWorkspace)) { t.match( req.body.policy, 'npm:node-uuid:20111130', @@ -252,6 +260,18 @@ export const YarnWorkspacesTests: AcceptanceTests = { 'Tested 6 projects', ); let policyCount = 0; + const applesWorkspace = + process.platform === 'win32' + ? '\\apples\\package.json' + : 'apples/package.json'; + const tomatoesWorkspace = + process.platform === 'win32' + ? '\\tomatoes\\package.json' + : 'tomatoes/package.json'; + const rootWorkspace = + process.platform === 'win32' + ? '\\yarn-workspaces\\package.json' + : 'yarn-workspaces/package.json'; params.server.popRequests(3).forEach((req) => { t.equal(req.method, 'POST', 'makes POST request'); @@ -262,8 +282,7 @@ export const YarnWorkspacesTests: AcceptanceTests = { ); t.match(req.url, '/api/v1/test-dep-graph', 'posts to correct url'); t.ok(req.body.depGraph, 'body contains depGraph'); - - if (req.body.targetFileRelativePath.endsWith('apples/package.json')) { + if (req.body.targetFileRelativePath.endsWith(applesWorkspace)) { t.match( req.body.policy, 'npm:node-uuid:20160328', @@ -272,14 +291,10 @@ export const YarnWorkspacesTests: AcceptanceTests = { t.ok(req.body.policy, 'body contains policy'); policyCount += 1; } else if ( - req.body.targetFileRelativePath.endsWith('tomatoes/package.json') + req.body.targetFileRelativePath.endsWith(tomatoesWorkspace) ) { t.notOk(req.body.policy, 'body does not contain policy'); - } else if ( - req.body.targetFileRelativePath.endsWith( - 'yarn-workspaces/package.json', - ) - ) { + } else if (req.body.targetFileRelativePath.endsWith(rootWorkspace)) { t.match( req.body.policy, 'npm:node-uuid:20111130', From 20a64bb44483241d84888779851109184357c475 Mon Sep 17 00:00:00 2001 From: ghe Date: Mon, 29 Jun 2020 11:28:05 +0100 Subject: [PATCH 7/9] chore: refactor options validation, add types & move --- src/cli/args.ts | 28 +++++--- src/cli/index.ts | 179 ++++++++++++++++++++++++----------------------- src/lib/types.ts | 34 +++++++++ 3 files changed, 145 insertions(+), 96 deletions(-) diff --git a/src/cli/args.ts b/src/cli/args.ts index 9bc7d51ae53..022a6acb2f3 100644 --- a/src/cli/args.ts +++ b/src/cli/args.ts @@ -3,6 +3,10 @@ import { MethodResult } from './commands/types'; import debugModule = require('debug'); import { parseMode, displayModeHelp } from './modes'; +import { + SupportedCliCommands, + SupportedUserReachableFacingCliArgs, +} from '../lib/types'; export declare interface Global extends NodeJS.Global { ignoreUnknownCA: boolean; @@ -157,19 +161,24 @@ export function args(rawArgv: string[]): Args { argv._.push(command); } + const commands: SupportedCliCommands[] = [ + 'protect', + 'test', + 'monitor', + 'wizard', + 'ignore', + 'woof', + ]; // TODO decide why we can't do this cart blanche... - if ( - ['protect', 'test', 'monitor', 'wizard', 'ignore', 'woof'].indexOf( - command, - ) !== -1 - ) { + if (commands.indexOf(command as SupportedCliCommands) !== -1) { // copy all the options across to argv._ as an object argv._.push(argv); } - // arguments that needs transformation from dash-case to camelCase - // should be added here - for (const dashedArg of [ + // TODO: eventually all arguments should be transformed like this. + const argumentsToTransform: Array> = [ 'package-manager', 'packages-folder', 'severity-threshold', @@ -184,7 +193,8 @@ export function args(rawArgv: string[]): Args { 'yarn-workspaces', 'detection-depth', 'reachable-vulns', - ]) { + ]; + for (const dashedArg of argumentsToTransform) { if (argv[dashedArg]) { const camelCased = dashToCamelCase(dashedArg); argv[camelCased] = argv[dashedArg]; diff --git a/src/cli/index.ts b/src/cli/index.ts index 87f5b3de5ee..b85ec69daff 100755 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -32,6 +32,7 @@ import { createDirectory, writeContentsToFileSwallowingErrors, } from '../lib/json-file-output'; +import { Options, TestOptions, MonitorOptions } from '../lib/types'; const debug = Debug('snyk'); const EXIT_CODES = { @@ -217,6 +218,8 @@ function checkPaths(args) { } } +type AllSupportedCliOptions = Options & MonitorOptions & TestOptions; + async function main() { updateCheck(); checkRuntime(); @@ -227,93 +230,10 @@ async function main() { let exitCode = EXIT_CODES.ERROR; try { modeValidation(args); - - if (args.options.scanAllUnmanaged && args.options.file) { - throw new UnsupportedOptionCombinationError([ - 'file', - 'scan-all-unmanaged', - ]); - } - - if (args.options['project-name'] && args.options.allProjects) { - throw new UnsupportedOptionCombinationError([ - 'project-name', - 'all-projects', - ]); - } - - if (args.options['project-name'] && args.options.yarnWorkspaces) { - throw new UnsupportedOptionCombinationError([ - 'project-name', - 'yarn-workspaces', - ]); - } - - if (args.options.file && args.options.yarnWorkspaces) { - throw new UnsupportedOptionCombinationError(['file', 'yarn-workspaces']); - } - - if (args.options.file && args.options.allProjects) { - throw new UnsupportedOptionCombinationError(['file', 'all-projects']); - } - - if (args.options.yarnWorkspaces && args.options.allProjects) { - throw new UnsupportedOptionCombinationError([ - 'yarn-workspaces', - 'all-projects', - ]); - } - - if (args.options.packageManager && args.options.yarnWorkspaces) { - throw new UnsupportedOptionCombinationError([ - 'package-manager', - 'yarn-workspaces', - ]); - } - - if (args.options.packageManager && args.options.allProjects) { - throw new UnsupportedOptionCombinationError([ - 'package-manager', - 'all-projects', - ]); - } - - if (args.options.docker && args.options.allProjects) { - throw new UnsupportedOptionCombinationError(['docker', 'all-projects']); - } - - if (args.options.docker && args.options.yarnWorkspaces) { - throw new UnsupportedOptionCombinationError([ - 'docker', - 'yarn-workspaces', - ]); - } - - if (args.options.allSubProjects && args.options.yarnWorkspaces) { - throw new UnsupportedOptionCombinationError([ - 'all-sub-projects', - 'yarn-workspaces', - ]); - } - - if (args.options.allSubProjects && args.options.allProjects) { - throw new UnsupportedOptionCombinationError([ - 'all-sub-projects', - 'all-projects', - ]); - } - - if (args.options.exclude) { - if (typeof args.options.exclude !== 'string') { - throw new ExcludeFlagBadInputError(); - } - if (!args.options.allProjects) { - throw new OptionMissingErrorError('--exclude', '--all-projects'); - } - if (args.options.exclude.indexOf(pathLib.sep) > -1) { - throw new ExcludeFlagInvalidInputError(); - } - } + // TODO: fix this, we do transformation to options and teh type doesn't reflect it + validateUnsupportedOptionCombinations( + (args.options as unknown) as AllSupportedCliOptions, + ); if ( args.options.file && @@ -383,3 +303,88 @@ if (module.parent) { // eslint-disable-next-line id-blacklist module.exports = cli; } + +function validateUnsupportedOptionCombinations( + options: Options & TestOptions & MonitorOptions, +): void { + if (options.scanAllUnmanaged && options.file) { + throw new UnsupportedOptionCombinationError(['file', 'scan-all-unmanaged']); + } + + if (options['project-name'] && options.allProjects) { + throw new UnsupportedOptionCombinationError([ + 'project-name', + 'all-projects', + ]); + } + + if (options['project-name'] && options.yarnWorkspaces) { + throw new UnsupportedOptionCombinationError([ + 'project-name', + 'yarn-workspaces', + ]); + } + + if (options.file && options.yarnWorkspaces) { + throw new UnsupportedOptionCombinationError(['file', 'yarn-workspaces']); + } + + if (options.file && options.allProjects) { + throw new UnsupportedOptionCombinationError(['file', 'all-projects']); + } + + if (options.yarnWorkspaces && options.allProjects) { + throw new UnsupportedOptionCombinationError([ + 'yarn-workspaces', + 'all-projects', + ]); + } + + if (options.packageManager && options.yarnWorkspaces) { + throw new UnsupportedOptionCombinationError([ + 'package-manager', + 'yarn-workspaces', + ]); + } + + if (options.packageManager && options.allProjects) { + throw new UnsupportedOptionCombinationError([ + 'package-manager', + 'all-projects', + ]); + } + + if (options.docker && options.allProjects) { + throw new UnsupportedOptionCombinationError(['docker', 'all-projects']); + } + + if (options.docker && options.yarnWorkspaces) { + throw new UnsupportedOptionCombinationError(['docker', 'yarn-workspaces']); + } + + if (options.allSubProjects && options.yarnWorkspaces) { + throw new UnsupportedOptionCombinationError([ + 'all-sub-projects', + 'yarn-workspaces', + ]); + } + + if (options.allSubProjects && options.allProjects) { + throw new UnsupportedOptionCombinationError([ + 'all-sub-projects', + 'all-projects', + ]); + } + + if (options.exclude) { + if (typeof options.exclude !== 'string') { + throw new ExcludeFlagBadInputError(); + } + if (!options.allProjects) { + throw new OptionMissingErrorError('--exclude', '--all-projects'); + } + if (options.exclude.indexOf(pathLib.sep) > -1) { + throw new ExcludeFlagInvalidInputError(); + } + } +} diff --git a/src/lib/types.ts b/src/lib/types.ts index 8c01fd956ec..6046a3f874b 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -129,3 +129,37 @@ export interface SpinnerOptions { } export type SupportedProjectTypes = IacProjectTypes | SupportedPackageManagers; + +export type SupportedUserReachableFacingCliArgs = + | 'severity-threshold' + | 'prune-repeated-subdependencies' + | 'ignore-policy' + | 'trust-policies' + | 'docker' + | 'file' + | 'policy' + | 'fail-on' + | 'reachable-vulns' + | 'json' + | 'package-manager' + | 'packages-folder' + | 'severity-threshold' + | 'strict-out-of-sync' + | 'all-sub-projects' + | 'sub-project' + | 'gradle-sub-project' + | 'skip-unresolved' + | 'scan-all-unmanaged' + | 'fail-on' + | 'all-projects' + | 'yarn-workspaces' + | 'detection-depth' + | 'reachable-vulns'; + +export type SupportedCliCommands = + | 'protect' + | 'test' + | 'monitor' + | 'wizard' + | 'ignore' + | 'woof'; From a199f93fb8b365debd4a3f75939b94a8efa518d2 Mon Sep 17 00:00:00 2001 From: ghe Date: Mon, 29 Jun 2020 11:50:45 +0100 Subject: [PATCH 8/9] chore: simplify options validation --- help/help.txt | 4 +- src/cli/index.ts | 118 ++++++++----------- src/lib/errors/exclude-flag-invalid-input.ts | 2 +- src/lib/errors/option-missing-error.ts | 6 +- src/lib/types.ts | 2 + test/acceptance/cli-args.test.ts | 12 +- 6 files changed, 67 insertions(+), 77 deletions(-) diff --git a/help/help.txt b/help/help.txt index f583da86764..778cbbfb532 100644 --- a/help/help.txt +++ b/help/help.txt @@ -121,8 +121,8 @@ npm options: Yarn options: --strict-out-of-sync= Prevent testing out of sync lockfiles. Defaults to true. - --yarn-workspaces Detect and scan yarn workspaces. Similar to --all-projects you can specify how - many sub-directories to search & exclude some directories. + --yarn-workspaces Detect and scan yarn workspaces. You can specify how many sub-directories to search using --detection-depth and exclude directories using --exclude. + CocoaPods options: --strict-out-of-sync= diff --git a/src/cli/index.ts b/src/cli/index.ts index b85ec69daff..557ac399f69 100755 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -32,7 +32,12 @@ import { createDirectory, writeContentsToFileSwallowingErrors, } from '../lib/json-file-output'; -import { Options, TestOptions, MonitorOptions } from '../lib/types'; +import { + Options, + TestOptions, + MonitorOptions, + SupportedUserReachableFacingCliArgs, +} from '../lib/types'; const debug = Debug('snyk'); const EXIT_CODES = { @@ -305,84 +310,65 @@ if (module.parent) { } function validateUnsupportedOptionCombinations( - options: Options & TestOptions & MonitorOptions, + options: AllSupportedCliOptions, ): void { + const unsupportedAllProjectsCombinations: { + [name: string]: SupportedUserReachableFacingCliArgs; + } = { + 'project-name': 'project-name', + file: 'file', + yarnWorkspaces: 'yarn-workspaces', + packageManager: 'package-manager', + docker: 'docker', + allSubProjects: 'all-sub-projects', + }; + + const unsupportedYarnWorkspacesCombinations: { + [name: string]: SupportedUserReachableFacingCliArgs; + } = { + 'project-name': 'project-name', + file: 'file', + packageManager: 'package-manager', + docker: 'docker', + allSubProjects: 'all-sub-projects', + }; + if (options.scanAllUnmanaged && options.file) { throw new UnsupportedOptionCombinationError(['file', 'scan-all-unmanaged']); } - if (options['project-name'] && options.allProjects) { - throw new UnsupportedOptionCombinationError([ - 'project-name', - 'all-projects', - ]); - } - - if (options['project-name'] && options.yarnWorkspaces) { - throw new UnsupportedOptionCombinationError([ - 'project-name', - 'yarn-workspaces', - ]); - } - - if (options.file && options.yarnWorkspaces) { - throw new UnsupportedOptionCombinationError(['file', 'yarn-workspaces']); - } - - if (options.file && options.allProjects) { - throw new UnsupportedOptionCombinationError(['file', 'all-projects']); - } - - if (options.yarnWorkspaces && options.allProjects) { - throw new UnsupportedOptionCombinationError([ - 'yarn-workspaces', - 'all-projects', - ]); - } - - if (options.packageManager && options.yarnWorkspaces) { - throw new UnsupportedOptionCombinationError([ - 'package-manager', - 'yarn-workspaces', - ]); - } - - if (options.packageManager && options.allProjects) { - throw new UnsupportedOptionCombinationError([ - 'package-manager', - 'all-projects', - ]); - } - - if (options.docker && options.allProjects) { - throw new UnsupportedOptionCombinationError(['docker', 'all-projects']); - } - - if (options.docker && options.yarnWorkspaces) { - throw new UnsupportedOptionCombinationError(['docker', 'yarn-workspaces']); - } - - if (options.allSubProjects && options.yarnWorkspaces) { - throw new UnsupportedOptionCombinationError([ - 'all-sub-projects', - 'yarn-workspaces', - ]); + if (options.allProjects) { + for (const option in unsupportedAllProjectsCombinations) { + if (options[option]) { + throw new UnsupportedOptionCombinationError([ + unsupportedAllProjectsCombinations[option], + 'all-projects', + ]); + } + } } - if (options.allSubProjects && options.allProjects) { - throw new UnsupportedOptionCombinationError([ - 'all-sub-projects', - 'all-projects', - ]); + if (options.yarnWorkspaces) { + for (const option in unsupportedYarnWorkspacesCombinations) { + if (options[option]) { + throw new UnsupportedOptionCombinationError([ + unsupportedAllProjectsCombinations[option], + 'yarn-workspaces', + ]); + } + } } if (options.exclude) { + if (!(options.allProjects || options.yarnWorkspaces)) { + throw new OptionMissingErrorError('--exclude', [ + '--yarn-workspaces', + '--all-projects', + ]); + } if (typeof options.exclude !== 'string') { throw new ExcludeFlagBadInputError(); } - if (!options.allProjects) { - throw new OptionMissingErrorError('--exclude', '--all-projects'); - } if (options.exclude.indexOf(pathLib.sep) > -1) { throw new ExcludeFlagInvalidInputError(); } diff --git a/src/lib/errors/exclude-flag-invalid-input.ts b/src/lib/errors/exclude-flag-invalid-input.ts index 6fb17f12111..78f4e4a6a42 100644 --- a/src/lib/errors/exclude-flag-invalid-input.ts +++ b/src/lib/errors/exclude-flag-invalid-input.ts @@ -3,7 +3,7 @@ import { CustomError } from './custom-error'; export class ExcludeFlagInvalidInputError extends CustomError { private static ERROR_CODE = 422; private static ERROR_MESSAGE = - 'The --exclude argument must be a comma seperated list of directory names and cannot contain a path.'; + 'The --exclude argument must be a comma separated list of directory names and cannot contain a path.'; constructor() { super(ExcludeFlagInvalidInputError.ERROR_MESSAGE); diff --git a/src/lib/errors/option-missing-error.ts b/src/lib/errors/option-missing-error.ts index 42df88eee66..5180c3cf6ef 100644 --- a/src/lib/errors/option-missing-error.ts +++ b/src/lib/errors/option-missing-error.ts @@ -1,8 +1,10 @@ import { CustomError } from './custom-error'; export class OptionMissingErrorError extends CustomError { - constructor(option: string, required: string) { - const msg = `The ${option} option can only be use in combination with ${required}.`; + constructor(option: string, required: string[]) { + const msg = `The ${option} option can only be use in combination with ${required + .sort() + .join(' or ')}.`; super(msg); this.code = 422; this.userMessage = msg; diff --git a/src/lib/types.ts b/src/lib/types.ts index 6046a3f874b..a5c773b4664 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -130,6 +130,7 @@ export interface SpinnerOptions { export type SupportedProjectTypes = IacProjectTypes | SupportedPackageManagers; +// TODO: finish typing this there are many more! export type SupportedUserReachableFacingCliArgs = | 'severity-threshold' | 'prune-repeated-subdependencies' @@ -154,6 +155,7 @@ export type SupportedUserReachableFacingCliArgs = | 'all-projects' | 'yarn-workspaces' | 'detection-depth' + | 'project-name' | 'reachable-vulns'; export type SupportedCliCommands = diff --git a/test/acceptance/cli-args.test.ts b/test/acceptance/cli-args.test.ts index 5619838a4c2..3a8dbb8cdf6 100644 --- a/test/acceptance/cli-args.test.ts +++ b/test/acceptance/cli-args.test.ts @@ -129,7 +129,7 @@ argsNotAllowedWithYarnWorkspaces.forEach((arg) => { if (err) { throw err; } - t.match( + t.deepEqual( stdout.trim(), `The following option combination is not currently supported: ${arg} + yarn-workspaces`, 'when using test', @@ -139,7 +139,7 @@ argsNotAllowedWithYarnWorkspaces.forEach((arg) => { if (err) { throw err; } - t.match( + t.deepEqual( stdout.trim(), `The following option combination is not currently supported: ${arg} + yarn-workspaces`, 'when using monitor', @@ -163,7 +163,7 @@ argsNotAllowedWithAllProjects.forEach((arg) => { if (err) { throw err; } - t.match( + t.deepEqual( stdout.trim(), `The following option combination is not currently supported: ${arg} + all-projects`, 'when using test', @@ -173,7 +173,7 @@ argsNotAllowedWithAllProjects.forEach((arg) => { if (err) { throw err; } - t.match( + t.deepEqual( stdout.trim(), `The following option combination is not currently supported: ${arg} + all-projects`, 'when using monitor', @@ -190,7 +190,7 @@ test('`test --exclude without --all-project displays error message`', (t) => { } t.equals( stdout.trim(), - 'The --exclude option can only be use in combination with --all-projects.', + 'The --exclude option can only be use in combination with --all-projects or --yarn-workspaces.', ); }); }); @@ -219,7 +219,7 @@ test('`test --exclude=path/to/dir displays error message`', (t) => { } t.equals( stdout.trim(), - 'The --exclude argument must be a comma seperated list of directory names and cannot contain a path.', + 'The --exclude argument must be a comma separated list of directory names and cannot contain a path.', ); }, ); From 5f7bee6e75a9bd184fb3c228ef281c0d6c56ae4a Mon Sep 17 00:00:00 2001 From: ghe Date: Mon, 29 Jun 2020 14:01:56 +0100 Subject: [PATCH 9/9] test: add empty package.json --- test/acceptance/workspaces/package.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 test/acceptance/workspaces/package.json diff --git a/test/acceptance/workspaces/package.json b/test/acceptance/workspaces/package.json new file mode 100644 index 00000000000..2a808d0ee09 --- /dev/null +++ b/test/acceptance/workspaces/package.json @@ -0,0 +1,11 @@ +{ + "name": "workspaces", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +}