diff --git a/src/lib/policy/find-and-load-policy.ts b/src/lib/policy/find-and-load-policy.ts index 9b896853d5a..4e8727769c1 100644 --- a/src/lib/policy/find-and-load-policy.ts +++ b/src/lib/policy/find-and-load-policy.ts @@ -19,7 +19,9 @@ export async function findAndLoadPolicy( const isDocker = scanType === 'docker'; const isNodeProject = ['npm', 'yarn'].includes(scanType); // monitor - let policyLocations: string[] = [options['policy-path'] || scannedProjectFolder || root]; + let policyLocations: string[] = [ + options['policy-path'] || scannedProjectFolder || root, + ]; if (isDocker) { policyLocations = policyLocations.filter((loc) => loc !== root); } else if (isNodeProject) { diff --git a/test/acceptance/cli-monitor/cli-monitor.all-projects.spec.ts b/test/acceptance/cli-monitor/cli-monitor.all-projects.spec.ts index 95a1f921a1d..4bb744822b1 100644 --- a/test/acceptance/cli-monitor/cli-monitor.all-projects.spec.ts +++ b/test/acceptance/cli-monitor/cli-monitor.all-projects.spec.ts @@ -17,31 +17,31 @@ export const AllProjectsTests: AcceptanceTests = { utils, ) => async (t) => { utils.chdirWorkspaces(); - await params.cli.monitor('mono-repo-with-ignores ', { + await params.cli.monitor('mono-repo-with-ignores', { allProjects: true, - detectionDepth: 1, + detectionDepth: 2, }); - - params.server.popRequests(2).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/monitor', 'posts to correct url'); - t.ok(req.body.depGraph, 'body contains depGraph'); - t.match( - req.body.policy, - 'npm:node-uuid:20160328', - 'body contains policy', - ); - t.match( - req.body.depGraph.pkgManager.name, - /(npm)/, - 'depGraph has package manager', - ); + // Pop all calls to server and filter out calls to `featureFlag` endpoint + const requests = params.server + .popRequests(4) + .filter((req) => req.url.includes('/monitor/')); + let policyCount = 0; + requests.forEach((req) => { + const vulnerableFolderPath = + process.platform === 'win32' + ? 'vulnerable\\package-lock.json' + : 'vulnerable/package-lock.json'; + + if (req.body.targetFileRelativePath.endsWith(vulnerableFolderPath)) { + t.match( + req.body.policy, + 'npm:node-uuid:20160328', + 'body contains policy', + ); + policyCount += 1; + } }); + t.equal(policyCount, 1, 'one policy found'); }, '`monitor mono-repo-project --all-projects --detection-depth=1`': ( params, diff --git a/test/acceptance/cli-test/cli-test.all-projects.spec.ts b/test/acceptance/cli-test/cli-test.all-projects.spec.ts index c160608f9ee..cdaa3022ce2 100644 --- a/test/acceptance/cli-test/cli-test.all-projects.spec.ts +++ b/test/acceptance/cli-test/cli-test.all-projects.spec.ts @@ -33,11 +33,11 @@ export const AllProjectsTests: 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( - 'vulnerable/package-lock.json', - ) - ) { + const vulnerableFolderPath = + process.platform === 'win32' + ? 'vulnerable\\package-lock.json' + : 'vulnerable/package-lock.json'; + if (req.body.targetFileRelativePath.endsWith(vulnerableFolderPath)) { t.match( req.body.policy, 'npm:node-uuid:20160328', @@ -68,862 +68,748 @@ export const AllProjectsTests: AcceptanceTests = { 'contains target file package-lock.json', ); }, - '`test mono-repo-project with lockfiles --all-projects`': ( - params, - utils, - ) => async (t) => { - utils.chdirWorkspaces(); - - // mock python plugin becuase CI tooling doesn't have pipenv installed - const mockPlugin = { - async inspect() { - return { - plugin: { - targetFile: 'Pipfile', - name: 'snyk-python-plugin', - }, - package: {}, - }; - }, - }; - const loadPlugin = sinon.stub(params.plugins, 'loadPlugin'); - t.teardown(loadPlugin.restore); - loadPlugin.withArgs('pip').returns(mockPlugin); - loadPlugin.callThrough(); // don't mock other plugins + '`test mono-repo-project with lockfiles --all-projects`': ( + params, + utils, + ) => async (t) => { + utils.chdirWorkspaces(); - const result: CommandResult = await params.cli.test('mono-repo-project', { - allProjects: true, - detectionDepth: 1, - skipUnresolved: true, - }); - t.ok(loadPlugin.withArgs('rubygems').calledOnce, 'calls rubygems plugin'); - t.ok(loadPlugin.withArgs('npm').calledOnce, 'calls npm plugin'); - t.ok(loadPlugin.withArgs('maven').calledOnce, 'calls maven plugin'); - t.ok(loadPlugin.withArgs('nuget').calledOnce, 'calls nuget plugin'); - t.ok(loadPlugin.withArgs('paket').calledOnce, 'calls nuget plugin'); - t.ok(loadPlugin.withArgs('pip').calledOnce, 'calls pip plugin'); - - params.server.popRequests(6).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.match( - req.body.depGraph.pkgManager.name, - /(npm|rubygems|maven|nuget|paket|pip)/, - 'depGraph has package manager', - ); - }); - // results should contain test results from both package managers + // mock python plugin becuase CI tooling doesn't have pipenv installed + const mockPlugin = { + async inspect() { + return { + plugin: { + targetFile: 'Pipfile', + name: 'snyk-python-plugin', + }, + package: {}, + }; + }, + }; + const loadPlugin = sinon.stub(params.plugins, 'loadPlugin'); + t.teardown(loadPlugin.restore); + loadPlugin.withArgs('pip').returns(mockPlugin); + loadPlugin.callThrough(); // don't mock other plugins - t.match( - result.getDisplayResults(), - 'Package manager: rubygems', - 'contains package manager rubygems', - ); - t.match( - result.getDisplayResults(), - 'Target file: Gemfile.lock', - 'contains target file Gemfile.lock', - ); - t.match( - result.getDisplayResults(), - 'Project name: shallow-goof', - 'contains correct project name for npm', - ); - t.match( - result.getDisplayResults(), - 'Package manager: npm', - 'contains package manager npm', - ); - t.match( - result.getDisplayResults(), - 'Target file: package-lock.json', - 'contains target file package-lock.json', - ); - t.match( - result.getDisplayResults(), - 'Package manager: maven', - 'contains package manager maven', - ); - t.match( - result.getDisplayResults(), - 'Target file: pom.xml', - 'contains target file pom.xml', + const result: CommandResult = await params.cli.test('mono-repo-project', { + allProjects: true, + detectionDepth: 1, + skipUnresolved: true, + }); + t.ok(loadPlugin.withArgs('rubygems').calledOnce, 'calls rubygems plugin'); + t.ok(loadPlugin.withArgs('npm').calledOnce, 'calls npm plugin'); + t.ok(loadPlugin.withArgs('maven').calledOnce, 'calls maven plugin'); + t.ok(loadPlugin.withArgs('nuget').calledOnce, 'calls nuget plugin'); + t.ok(loadPlugin.withArgs('paket').calledOnce, 'calls nuget plugin'); + t.ok(loadPlugin.withArgs('pip').calledOnce, 'calls pip plugin'); + + params.server.popRequests(6).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.match( - result.getDisplayResults(), - 'Target file: Pipfile', - 'contains target file Pipfile', + req.body.depGraph.pkgManager.name, + /(npm|rubygems|maven|nuget|paket|pip)/, + 'depGraph has package manager', ); - }, - - '`test mono-repo-project --all-projects --detection-depth=3`': ( - params, - utils, - ) => async (t) => { - utils.chdirWorkspaces(); - - // mock python plugin becuase CI tooling doesn't have pipenv installed - const mockPipfile = { - async inspect() { - return { - plugin: { - targetFile: 'Pipfile', - name: 'snyk-python-plugin', - }, - package: {}, - }; - }, - }; - const mockRequirements = { - async inspect() { - return { - plugin: { - targetFile: 'python-app-with-req-file/requirements.txt', - name: 'snyk-python-plugin', - }, - package: {}, - }; - }, - }; - const loadPlugin = sinon.stub(params.plugins, 'loadPlugin'); - t.teardown(loadPlugin.restore); - // detect pip plugin called only with Pipfile (and not requirement.txt) - loadPlugin - .withArgs('pip', sinon.match.has('file', 'Pipfile')) - .returns(mockPipfile) - .withArgs( - 'pip', - sinon.match.has('file', 'python-app-with-req-file/requirements.txt'), - ) - .returns(mockRequirements); - loadPlugin.callThrough(); // don't mock other plugins - - const result: CommandResult = await params.cli.test('mono-repo-project', { - allProjects: true, - detectionDepth: 3, - allowMissing: true, // allow requirements.txt to pass when deps not installed - }); + }); + // results should contain test results from both package managers - t.equals( - loadPlugin.withArgs('rubygems').callCount, - 2, - 'calls rubygems plugin', - ); - t.equals(loadPlugin.withArgs('npm').callCount, 2, 'calls npm plugin'); - t.ok(loadPlugin.withArgs('maven').calledOnce, 'calls maven plugin'); - t.ok(loadPlugin.withArgs('nuget').calledOnce, 'calls nuget plugin'); - t.ok(loadPlugin.withArgs('paket').calledOnce, 'calls nuget plugin'); - t.equals(loadPlugin.withArgs('pip').callCount, 2, 'calls pip plugin'); - - params.server.popRequests(9).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.match( - req.body.depGraph.pkgManager.name, - /(npm|rubygems|maven|nuget|paket|pip)/, - 'depGraph has package manager', - ); - }); + t.match( + result.getDisplayResults(), + 'Package manager: rubygems', + 'contains package manager rubygems', + ); + t.match( + result.getDisplayResults(), + 'Target file: Gemfile.lock', + 'contains target file Gemfile.lock', + ); + t.match( + result.getDisplayResults(), + 'Project name: shallow-goof', + 'contains correct project name for npm', + ); + t.match( + result.getDisplayResults(), + 'Package manager: npm', + 'contains package manager npm', + ); + t.match( + result.getDisplayResults(), + 'Target file: package-lock.json', + 'contains target file package-lock.json', + ); + t.match( + result.getDisplayResults(), + 'Package manager: maven', + 'contains package manager maven', + ); + t.match( + result.getDisplayResults(), + 'Target file: pom.xml', + 'contains target file pom.xml', + ); + t.match( + result.getDisplayResults(), + 'Target file: Pipfile', + 'contains target file Pipfile', + ); + }, - // ruby - t.match( - result.getDisplayResults(), - 'Package manager: rubygems', - 'contains package manager rubygems', - ); - t.match( - result.getDisplayResults(), - 'Target file: Gemfile.lock', - 'contains target file Gemfile.lock', - ); - t.match( - result.getDisplayResults(), - `Target file: bundler-app${path.sep}Gemfile.lock`, - `contains target file bundler-app${path.sep}Gemfile.lock`, - ); + '`test mono-repo-project --all-projects --detection-depth=3`': ( + params, + utils, + ) => async (t) => { + utils.chdirWorkspaces(); - // npm - t.match( - result.getDisplayResults(), - 'Project name: shallow-goof', - 'contains correct project name for npm', - ); - t.match( - result.getDisplayResults(), - 'Project name: goof', - 'contains correct project name for npm', - ); - t.match( - result.getDisplayResults(), - 'Package manager: npm', - 'contains package manager npm', - ); - t.match( - result.getDisplayResults(), - 'Target file: package-lock.json', - 'contains target file package-lock.json', - ); - t.match( - result.getDisplayResults(), - `Target file: npm-project${path.sep}package.json`, - `contains target file npm-project${path.sep}package.json`, - ); + // mock python plugin becuase CI tooling doesn't have pipenv installed + const mockPipfile = { + async inspect() { + return { + plugin: { + targetFile: 'Pipfile', + name: 'snyk-python-plugin', + }, + package: {}, + }; + }, + }; + const mockRequirements = { + async inspect() { + return { + plugin: { + targetFile: 'python-app-with-req-file/requirements.txt', + name: 'snyk-python-plugin', + }, + package: {}, + }; + }, + }; + const loadPlugin = sinon.stub(params.plugins, 'loadPlugin'); + t.teardown(loadPlugin.restore); + // detect pip plugin called only with Pipfile (and not requirement.txt) + loadPlugin + .withArgs('pip', sinon.match.has('file', 'Pipfile')) + .returns(mockPipfile) + .withArgs( + 'pip', + sinon.match.has('file', 'python-app-with-req-file/requirements.txt'), + ) + .returns(mockRequirements); + loadPlugin.callThrough(); // don't mock other plugins + + const result: CommandResult = await params.cli.test('mono-repo-project', { + allProjects: true, + detectionDepth: 3, + allowMissing: true, // allow requirements.txt to pass when deps not installed + }); - // maven - t.match( - result.getDisplayResults(), - 'Package manager: maven', - 'contains package manager maven', - ); - t.match( - result.getDisplayResults(), - 'Target file: pom.xml', - 'contains target file pom.xml', - ); + t.equals( + loadPlugin.withArgs('rubygems').callCount, + 2, + 'calls rubygems plugin', + ); + t.equals(loadPlugin.withArgs('npm').callCount, 2, 'calls npm plugin'); + t.ok(loadPlugin.withArgs('maven').calledOnce, 'calls maven plugin'); + t.ok(loadPlugin.withArgs('nuget').calledOnce, 'calls nuget plugin'); + t.ok(loadPlugin.withArgs('paket').calledOnce, 'calls nuget plugin'); + t.equals(loadPlugin.withArgs('pip').callCount, 2, 'calls pip plugin'); - // nuget - t.match( - result.getDisplayResults(), - 'Package manager: nuget', - 'contains package manager nuget', + params.server.popRequests(9).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.match( - result.getDisplayResults(), - 'Target file: packages.config', - 'contains target file packages.config', + req.body.depGraph.pkgManager.name, + /(npm|rubygems|maven|nuget|paket|pip)/, + 'depGraph has package manager', ); + }); - // paket - t.match( - result.getDisplayResults(), - 'Package manager: paket', - 'contains package manager paket', - ); - t.match( - result.getDisplayResults(), - 'Target file: paket.dependencies', - 'contains target file paket.dependencies', - ); + // ruby + t.match( + result.getDisplayResults(), + 'Package manager: rubygems', + 'contains package manager rubygems', + ); + t.match( + result.getDisplayResults(), + 'Target file: Gemfile.lock', + 'contains target file Gemfile.lock', + ); + t.match( + result.getDisplayResults(), + `Target file: bundler-app${path.sep}Gemfile.lock`, + `contains target file bundler-app${path.sep}Gemfile.lock`, + ); - // pip - t.match( - result.getDisplayResults(), - 'Package manager: pip', - 'contains package manager pip', - ); - t.match( - result.getDisplayResults(), - 'Target file: Pipfile', - 'contains target file Pipfile', + // npm + t.match( + result.getDisplayResults(), + 'Project name: shallow-goof', + 'contains correct project name for npm', + ); + t.match( + result.getDisplayResults(), + 'Project name: goof', + 'contains correct project name for npm', + ); + t.match( + result.getDisplayResults(), + 'Package manager: npm', + 'contains package manager npm', + ); + t.match( + result.getDisplayResults(), + 'Target file: package-lock.json', + 'contains target file package-lock.json', + ); + t.match( + result.getDisplayResults(), + `Target file: npm-project${path.sep}package.json`, + `contains target file npm-project${path.sep}package.json`, + ); + + // maven + t.match( + result.getDisplayResults(), + 'Package manager: maven', + 'contains package manager maven', + ); + t.match( + result.getDisplayResults(), + 'Target file: pom.xml', + 'contains target file pom.xml', + ); + + // nuget + t.match( + result.getDisplayResults(), + 'Package manager: nuget', + 'contains package manager nuget', + ); + t.match( + result.getDisplayResults(), + 'Target file: packages.config', + 'contains target file packages.config', + ); + + // paket + t.match( + result.getDisplayResults(), + 'Package manager: paket', + 'contains package manager paket', + ); + t.match( + result.getDisplayResults(), + 'Target file: paket.dependencies', + 'contains target file paket.dependencies', + ); + + // pip + t.match( + result.getDisplayResults(), + 'Package manager: pip', + 'contains package manager pip', + ); + t.match( + result.getDisplayResults(), + 'Target file: Pipfile', + 'contains target file Pipfile', + ); + t.match( + result.getDisplayResults(), + `Target file: python-app-with-req-file${path.sep}requirements.txt`, + `contains target file python-app-with-req-file${path.sep}requirements.txt`, + ); + }, + + '`test mono-repo-project --all-projects and --file payloads are the same`': ( + params, + utils, + ) => async (t) => { + utils.chdirWorkspaces(); + + // mock python plugin becuase CI tooling doesn't have pipenv installed + const mockPlugin = { + async inspect() { + return { + plugin: { + targetFile: 'Pipfile', + name: 'snyk-python-plugin', + }, + package: {}, + }; + }, + }; + const loadPlugin = sinon.stub(params.plugins, 'loadPlugin'); + t.teardown(loadPlugin.restore); + loadPlugin.withArgs('pip').returns(mockPlugin); + loadPlugin.callThrough(); // don't mock other plugins + + await params.cli.test('mono-repo-project', { + allProjects: true, + detectionDepth: 1, + }); + + const requests = params.server.popRequests(6); + + // find each type of request + const rubyAll = requests.find( + (req) => req.body.depGraph.pkgManager.name === 'rubygems', + ); + const pipAll = requests.find( + (req) => req.body.depGraph.pkgManager.name === 'pip', + ); + const npmAll = requests.find( + (req) => req.body.depGraph.pkgManager.name === 'npm', + ); + const nugetAll = requests.find( + (req) => req.body.depGraph.pkgManager.name === 'nuget', + ); + const paketAll = requests.find( + (req) => req.body.depGraph.pkgManager.name === 'paket', + ); + const mavenAll = requests.find( + (req) => req.body.depGraph.pkgManager.name === 'maven', + ); + + await params.cli.test('mono-repo-project', { + file: 'Gemfile.lock', + }); + const rubyFile = params.server.popRequest(); + + await params.cli.test('mono-repo-project', { + file: 'Pipfile', + }); + const pipFile = params.server.popRequest(); + + await params.cli.test('mono-repo-project', { + file: 'paket.dependencies', + }); + const paketFile = params.server.popRequest(); + + await params.cli.test('mono-repo-project', { + file: 'packages.config', + }); + const nugetFile = params.server.popRequest(); + + await params.cli.test('mono-repo-project', { + file: 'package-lock.json', + }); + const npmFile = params.server.popRequest(); + + await params.cli.test('mono-repo-project', { + file: 'pom.xml', + }); + const mavenFile = params.server.popRequest(); + + t.same( + pipAll.body, + pipFile.body, + 'Same body for --all-projects and --file=Pipfile', + ); + + t.same( + rubyAll.body, + rubyFile.body, + 'Same body for --all-projects and --file=Gemfile.lock', + ); + + t.same( + npmAll.body, + npmFile.body, + 'Same body for --all-projects and --file=package-lock.json', + ); + + t.same( + paketAll.body, + paketFile.body, + 'Same body for --all-projects and --file=package-lock.json', + ); + + t.same( + nugetAll.body, + nugetFile.body, + 'Same body for --all-projects and --file=package-lock.json', + ); + t.same( + mavenAll.body, + mavenFile.body, + 'Same body for --all-projects and --file=pom.xml', + ); + }, + + '`test maven-multi-app --all-projects --detection-depth=2`': ( + params, + utils, + ) => async (t) => { + utils.chdirWorkspaces(); + const spyPlugin = sinon.spy(params.plugins, 'loadPlugin'); + t.teardown(spyPlugin.restore); + + const result: CommandResult = await params.cli.test('maven-multi-app', { + allProjects: true, + detectionDepth: 2, + }); + + t.ok(spyPlugin.withArgs('maven').calledTwice, 'calls maven plugin'); + t.ok( + spyPlugin.withArgs('rubygems').notCalled, + 'did not call rubygems plugin', + ); + t.ok(spyPlugin.withArgs('npm').notCalled, 'did not call npm plugin'); + params.server.popRequests(2).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.match( - result.getDisplayResults(), - `Target file: python-app-with-req-file${path.sep}requirements.txt`, - `contains target file python-app-with-req-file${path.sep}requirements.txt`, + req.body.depGraph.pkgManager.name, + /maven/, + 'depGraph has package manager', ); - }, - - '`test mono-repo-project --all-projects and --file payloads are the same`': ( - params, - utils, - ) => async (t) => { - utils.chdirWorkspaces(); - - // mock python plugin becuase CI tooling doesn't have pipenv installed - const mockPlugin = { - async inspect() { - return { - plugin: { - targetFile: 'Pipfile', - name: 'snyk-python-plugin', - }, - package: {}, - }; - }, - }; - const loadPlugin = sinon.stub(params.plugins, 'loadPlugin'); - t.teardown(loadPlugin.restore); - loadPlugin.withArgs('pip').returns(mockPlugin); - loadPlugin.callThrough(); // don't mock other plugins + }); + t.match( + result.getDisplayResults(), + 'Package manager: maven', + 'contains package manager maven', + ); + t.match( + result.getDisplayResults(), + 'Target file: pom.xml', + 'contains target file pom.xml', + ); + t.match( + result.getDisplayResults(), + `Target file: simple-child${path.sep}pom.xml`, + `contains target file simple-child${path.sep}pom.xml`, + ); + }, - await params.cli.test('mono-repo-project', { - allProjects: true, - detectionDepth: 1, - }); + '`test large-mono-repo with --all-projects and --detection-depth=2`': ( + params, + utils, + ) => async (t) => { + utils.chdirWorkspaces(); + const spyPlugin = sinon.spy(params.plugins, 'loadPlugin'); + t.teardown(spyPlugin.restore); + await params.cli.test('large-mono-repo', { + allProjects: true, + detectionDepth: 2, + }); + t.equals( + spyPlugin.withArgs('rubygems').callCount, + 1, + 'calls rubygems plugin once', + ); + t.equals( + spyPlugin.withArgs('npm').callCount, + 19, + 'calls npm plugin 19 times', + ); + t.equals( + spyPlugin.withArgs('maven').callCount, + 1, + 'calls maven plugin once', + ); + }, - const requests = params.server.popRequests(6); + '`test large-mono-repo with --all-projects and --detection-depth=7`': ( + params, + utils, + ) => async (t) => { + utils.chdirWorkspaces(); + const spyPlugin = sinon.spy(params.plugins, 'loadPlugin'); + t.teardown(spyPlugin.restore); + await params.cli.test('large-mono-repo', { + allProjects: true, + detectionDepth: 7, + }); + t.equals( + spyPlugin.withArgs('rubygems').callCount, + 19, + 'calls rubygems plugin 19 times', + ); + t.equals( + spyPlugin.withArgs('npm').callCount, + 19, + 'calls npm plugin 19 times', + ); + t.equals( + spyPlugin.withArgs('maven').callCount, + 6, + 'calls maven plugin 6 times', + ); + }, - // find each type of request - const rubyAll = requests.find( - (req) => req.body.depGraph.pkgManager.name === 'rubygems', - ); - const pipAll = requests.find( - (req) => req.body.depGraph.pkgManager.name === 'pip', - ); - const npmAll = requests.find( - (req) => req.body.depGraph.pkgManager.name === 'npm', - ); - const nugetAll = requests.find( - (req) => req.body.depGraph.pkgManager.name === 'nuget', - ); - const paketAll = requests.find( - (req) => req.body.depGraph.pkgManager.name === 'paket', + '`test mono-repo-project-manifests-only --all-projects`': ( + params, + utils, + ) => async (t) => { + utils.chdirWorkspaces(); + const result: CommandResult = await params.cli.test( + 'mono-repo-project-manifests-only', + { + allProjects: true, + }, + ); + 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', ); - const mavenAll = requests.find( - (req) => req.body.depGraph.pkgManager.name === 'maven', + t.match(req.url, '/api/v1/test-dep-graph', 'posts to correct url'); + t.ok(req.body.depGraph, 'body contains depGraph'); + t.match( + req.body.depGraph.pkgManager.name, + /(npm|rubygems|maven)/, + 'depGraph has package manager', ); + }); - await params.cli.test('mono-repo-project', { - file: 'Gemfile.lock', - }); - const rubyFile = params.server.popRequest(); + // results should contain test results from all package managers + t.match( + result.getDisplayResults(), + 'Package manager: rubygems', + 'contains package manager rubygems', + ); + t.match( + result.getDisplayResults(), + 'Target file: Gemfile.lock', + 'contains target file Gemfile.lock', + ); + t.match( + result.getDisplayResults(), + 'Package manager: npm', + 'contains package manager npm', + ); + t.match( + result.getDisplayResults(), + 'Target file: package-lock.json', + 'contains target file package-lock.json', + ); + t.match( + result.getDisplayResults(), + 'Package manager: maven', + 'contains package manager maven', + ); + t.match( + result.getDisplayResults(), + 'Target file: pom.xml', + 'contains target file pom.xml', + ); + }, - await params.cli.test('mono-repo-project', { - file: 'Pipfile', - }); - const pipFile = params.server.popRequest(); + '`test ruby-app --all-projects`': (params, utils) => async (t) => { + utils.chdirWorkspaces(); + const spyPlugin = sinon.spy(params.plugins, 'loadPlugin'); + t.teardown(spyPlugin.restore); - await params.cli.test('mono-repo-project', { - file: 'paket.dependencies', - }); - const paketFile = params.server.popRequest(); + const res: CommandResult = await params.cli.test('ruby-app', { + allProjects: true, + }); - await params.cli.test('mono-repo-project', { - file: 'packages.config', - }); - const nugetFile = params.server.popRequest(); + t.ok(spyPlugin.withArgs('rubygems').calledOnce, 'calls rubygems plugin'); + t.notOk(spyPlugin.withArgs('npm').calledOnce, "doesn't call npm plugin"); + t.notOk( + spyPlugin.withArgs('maven').calledOnce, + "doesn't call maven plugin", + ); - await params.cli.test('mono-repo-project', { - file: 'package-lock.json', - }); - const npmFile = params.server.popRequest(); + t.match( + res.getDisplayResults(), + 'Package manager: rubygems', + 'contains package manager rubygems', + ); + t.match( + res.getDisplayResults(), + 'Target file: Gemfile.lock', + 'contains target file Gemfile.lock', + ); + }, - await params.cli.test('mono-repo-project', { - file: 'pom.xml', + '`test ruby-app-thresholds --all-projects --ignore-policy`': ( + params, + utils, + ) => async (t) => { + utils.chdirWorkspaces('ruby-app-thresholds'); + params.server.setNextResponse( + getWorkspaceJSON( + 'ruby-app-thresholds', + 'test-graph-result-medium-severity.json', + ), + ); + try { + await params.cli.test('./', { + 'ignore-policy': true, + allProjects: true, }); - const mavenFile = params.server.popRequest(); - - t.same( - pipAll.body, - pipFile.body, - 'Same body for --all-projects and --file=Pipfile', - ); - - t.same( - rubyAll.body, - rubyFile.body, - 'Same body for --all-projects and --file=Gemfile.lock', - ); - - t.same( - npmAll.body, - npmFile.body, - 'Same body for --all-projects and --file=package-lock.json', - ); - - t.same( - paketAll.body, - paketFile.body, - 'Same body for --all-projects and --file=package-lock.json', - ); - - t.same( - nugetAll.body, - nugetFile.body, - 'Same body for --all-projects and --file=package-lock.json', - ); - t.same( - mavenAll.body, - mavenFile.body, - 'Same body for --all-projects and --file=pom.xml', + t.fail('should have thrown'); + } catch (err) { + const req = params.server.popRequest(); + t.equal(req.query.ignorePolicy, 'true', 'should request ignore policy'); + const res = err.message; + t.match( + res, + 'Tested 7 dependencies for known vulnerabilities, found 5 vulnerabilities, 6 vulnerable paths.', + 'should display expected message', ); - }, + } + }, - '`test maven-multi-app --all-projects --detection-depth=2`': ( - params, - utils, - ) => async (t) => { - utils.chdirWorkspaces(); - const spyPlugin = sinon.spy(params.plugins, 'loadPlugin'); - t.teardown(spyPlugin.restore); + '`test large-mono-repo with --all-projects, --detection-depth=7 and --exclude=bundler-app,maven-project-1`': ( + params, + utils, + ) => async (t) => { + utils.chdirWorkspaces(); + const spyPlugin = sinon.spy(params.plugins, 'loadPlugin'); + t.teardown(spyPlugin.restore); + await params.cli.test('large-mono-repo', { + allProjects: true, + detectionDepth: 7, + exclude: 'bundler-app,maven-project-1', + }); + t.equals( + spyPlugin.withArgs('rubygems').callCount, + 0, + 'does not call rubygems', + ); + t.equals( + spyPlugin.withArgs('npm').callCount, + 19, + 'calls npm plugin 19 times', + ); + t.equals( + spyPlugin.withArgs('maven').callCount, + 1, + 'calls maven plugin once, excluding the rest', + ); + }, - const result: CommandResult = await params.cli.test('maven-multi-app', { + '`test empty --all-projects`': (params, utils) => async (t) => { + utils.chdirWorkspaces(); + try { + await params.cli.test('empty', { allProjects: true, - detectionDepth: 2, - }); - - t.ok(spyPlugin.withArgs('maven').calledTwice, 'calls maven plugin'); - t.ok( - spyPlugin.withArgs('rubygems').notCalled, - 'did not call rubygems plugin', - ); - t.ok(spyPlugin.withArgs('npm').notCalled, 'did not call npm plugin'); - params.server.popRequests(2).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.match( - req.body.depGraph.pkgManager.name, - /maven/, - 'depGraph has package manager', - ); }); + t.fail('expected an error to be thrown'); + } catch (err) { + const res = err.message; t.match( - result.getDisplayResults(), - 'Package manager: maven', - 'contains package manager maven', - ); - t.match( - result.getDisplayResults(), - 'Target file: pom.xml', - 'contains target file pom.xml', - ); - t.match( - result.getDisplayResults(), - `Target file: simple-child${path.sep}pom.xml`, - `contains target file simple-child${path.sep}pom.xml`, - ); - }, - - '`test large-mono-repo with --all-projects and --detection-depth=2`': ( - params, - utils, - ) => async (t) => { - utils.chdirWorkspaces(); - const spyPlugin = sinon.spy(params.plugins, 'loadPlugin'); - t.teardown(spyPlugin.restore); - await params.cli.test('large-mono-repo', { - allProjects: true, - detectionDepth: 2, - }); - t.equals( - spyPlugin.withArgs('rubygems').callCount, - 1, - 'calls rubygems plugin once', - ); - t.equals( - spyPlugin.withArgs('npm').callCount, - 19, - 'calls npm plugin 19 times', - ); - t.equals( - spyPlugin.withArgs('maven').callCount, - 1, - 'calls maven plugin once', - ); - }, - - '`test large-mono-repo with --all-projects and --detection-depth=7`': ( - params, - utils, - ) => async (t) => { - utils.chdirWorkspaces(); - const spyPlugin = sinon.spy(params.plugins, 'loadPlugin'); - t.teardown(spyPlugin.restore); - await params.cli.test('large-mono-repo', { - allProjects: true, - detectionDepth: 7, - }); - t.equals( - spyPlugin.withArgs('rubygems').callCount, - 19, - 'calls rubygems plugin 19 times', + res, + 'Could not detect supported target files', + 'should display expected message', ); - t.equals( - spyPlugin.withArgs('npm').callCount, - 19, - 'calls npm plugin 19 times', - ); - t.equals( - spyPlugin.withArgs('maven').callCount, - 6, - 'calls maven plugin 6 times', - ); - }, - - '`test mono-repo-project-manifests-only --all-projects`': ( - params, - utils, - ) => async (t) => { - utils.chdirWorkspaces(); - const result: CommandResult = await params.cli.test( - 'mono-repo-project-manifests-only', + } + }, + + '`test monorepo-with-nuget --all-projects with Nuget, Python, Go, Npm, Cocoapods`': ( + params, + utils, + ) => async (t) => { + utils.chdirWorkspaces(); + const mockPlugin = { + async inspect() { + return { + package: {}, + plugin: { + name: 'mock', + }, + }; + }, + }; + const loadPlugin = sinon.stub(params.plugins, 'loadPlugin'); + t.teardown(loadPlugin.restore); + // prevent plugin inspect from actually running (requires go to be installed) + loadPlugin.withArgs('golangdep').returns(mockPlugin); + loadPlugin.callThrough(); // don't mock other plugins + + try { + const res: CommandResult = await params.cli.test( + 'monorepo-with-nuget', { allProjects: true, + detectionDepth: 4, }, ); - 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.match( - req.body.depGraph.pkgManager.name, - /(npm|rubygems|maven)/, - 'depGraph has package manager', - ); - }); - - // results should contain test results from all package managers - t.match( - result.getDisplayResults(), - 'Package manager: rubygems', - 'contains package manager rubygems', - ); - t.match( - result.getDisplayResults(), - 'Target file: Gemfile.lock', - 'contains target file Gemfile.lock', - ); - t.match( - result.getDisplayResults(), - 'Package manager: npm', - 'contains package manager npm', - ); - t.match( - result.getDisplayResults(), - 'Target file: package-lock.json', - 'contains target file package-lock.json', - ); - t.match( - result.getDisplayResults(), - 'Package manager: maven', - 'contains package manager maven', + t.equal( + loadPlugin.withArgs('nuget').callCount, + 2, + 'calls nuget plugin twice', ); - t.match( - result.getDisplayResults(), - 'Target file: pom.xml', - 'contains target file pom.xml', + t.ok( + loadPlugin.withArgs('cocoapods').calledOnce, + 'calls cocoapods plugin', ); - }, - - '`test ruby-app --all-projects`': (params, utils) => async (t) => { - utils.chdirWorkspaces(); - const spyPlugin = sinon.spy(params.plugins, 'loadPlugin'); - t.teardown(spyPlugin.restore); - - const res: CommandResult = await params.cli.test('ruby-app', { - allProjects: true, - }); - - t.ok(spyPlugin.withArgs('rubygems').calledOnce, 'calls rubygems plugin'); - t.notOk(spyPlugin.withArgs('npm').calledOnce, "doesn't call npm plugin"); - t.notOk( - spyPlugin.withArgs('maven').calledOnce, - "doesn't call maven plugin", + t.ok(loadPlugin.withArgs('npm').calledOnce, 'calls npm plugin'); + t.ok( + loadPlugin.withArgs('golangdep').calledOnce, + 'calls golangdep plugin', ); - + t.ok(loadPlugin.withArgs('paket').calledOnce, 'calls nuget plugin'); t.match( res.getDisplayResults(), - 'Package manager: rubygems', - 'contains package manager rubygems', + /Tested 6 projects, no vulnerable paths were found./, + 'Six projects tested', ); t.match( res.getDisplayResults(), - 'Target file: Gemfile.lock', - 'contains target file Gemfile.lock', - ); - }, - - '`test ruby-app-thresholds --all-projects --ignore-policy`': ( - params, - utils, - ) => async (t) => { - utils.chdirWorkspaces('ruby-app-thresholds'); - params.server.setNextResponse( - getWorkspaceJSON( - 'ruby-app-thresholds', - 'test-graph-result-medium-severity.json', - ), - ); - try { - await params.cli.test('./', { - 'ignore-policy': true, - allProjects: true, - }); - t.fail('should have thrown'); - } catch (err) { - const req = params.server.popRequest(); - t.equal(req.query.ignorePolicy, 'true', 'should request ignore policy'); - const res = err.message; - t.match( - res, - 'Tested 7 dependencies for known vulnerabilities, found 5 vulnerabilities, 6 vulnerable paths.', - 'should display expected message', - ); - } - }, - - '`test large-mono-repo with --all-projects, --detection-depth=7 and --exclude=bundler-app,maven-project-1`': ( - params, - utils, - ) => async (t) => { - utils.chdirWorkspaces(); - const spyPlugin = sinon.spy(params.plugins, 'loadPlugin'); - t.teardown(spyPlugin.restore); - await params.cli.test('large-mono-repo', { - allProjects: true, - detectionDepth: 7, - exclude: 'bundler-app,maven-project-1', - }); - t.equals( - spyPlugin.withArgs('rubygems').callCount, - 0, - 'does not call rubygems', - ); - t.equals( - spyPlugin.withArgs('npm').callCount, - 19, - 'calls npm plugin 19 times', - ); - t.equals( - spyPlugin.withArgs('maven').callCount, - 1, - 'calls maven plugin once, excluding the rest', - ); - }, - - '`test empty --all-projects`': (params, utils) => async (t) => { - utils.chdirWorkspaces(); - try { - await params.cli.test('empty', { - allProjects: true, - }); - t.fail('expected an error to be thrown'); - } catch (err) { - const res = err.message; - t.match( - res, - 'Could not detect supported target files', - 'should display expected message', - ); - } - }, - - '`test monorepo-with-nuget --all-projects with Nuget, Python, Go, Npm, Cocoapods`': ( - params, - utils, - ) => async (t) => { - utils.chdirWorkspaces(); - const mockPlugin = { - async inspect() { - return { - package: {}, - plugin: { - name: 'mock', - }, - }; - }, - }; - const loadPlugin = sinon.stub(params.plugins, 'loadPlugin'); - t.teardown(loadPlugin.restore); - // prevent plugin inspect from actually running (requires go to be installed) - loadPlugin.withArgs('golangdep').returns(mockPlugin); - loadPlugin.callThrough(); // don't mock other plugins - - try { - const res: CommandResult = await params.cli.test( - 'monorepo-with-nuget', - { - allProjects: true, - detectionDepth: 4, - }, - ); - t.equal( - loadPlugin.withArgs('nuget').callCount, - 2, - 'calls nuget plugin twice', - ); - t.ok( - loadPlugin.withArgs('cocoapods').calledOnce, - 'calls cocoapods plugin', - ); - t.ok(loadPlugin.withArgs('npm').calledOnce, 'calls npm plugin'); - t.ok( - loadPlugin.withArgs('golangdep').calledOnce, - 'calls golangdep plugin', - ); - t.ok(loadPlugin.withArgs('paket').calledOnce, 'calls nuget plugin'); - t.match( - res.getDisplayResults(), - /Tested 6 projects, no vulnerable paths were found./, - 'Six projects tested', - ); - t.match( - res.getDisplayResults(), - `Target file: src${path.sep}paymentservice${path.sep}package-lock.json`, - 'Npm project targetFile is as expected', - ); - t.match( - res.getDisplayResults(), - `Target file: src${path.sep}cocoapods-app${path.sep}Podfile`, - 'Cocoapods project targetFile is as expected', - ); - t.match( - res.getDisplayResults(), - `Target file: src${path.sep}frontend${path.sep}Gopkg.lock`, - 'Go dep project targetFile is as expected', - ); - t.match( - res.getDisplayResults(), - `Target file: src${path.sep}cartservice-nuget${path.sep}obj${path.sep}project.assets.json`, - 'Nuget project targetFile is as expected', - ); - t.match( - res.getDisplayResults(), - `Target file: test${path.sep}nuget-app-4${path.sep}packages.config`, - 'Nuget project targetFile is as expected', - ); - t.match( - res.getDisplayResults(), - `Target file: test${path.sep}paket-app${path.sep}paket.dependencies`, - 'Paket project targetFile is as expected', - ); - - t.match( - res.getDisplayResults(), - 'Package manager: nuget', - 'Nuget package manager', - ); - t.match( - res.getDisplayResults(), - 'Package manager: cocoapods', - 'Cocoapods package manager', - ); - t.match( - res.getDisplayResults(), - 'Package manager: npm', - 'Npm package manager', - ); - t.match( - res.getDisplayResults(), - 'Package manager: golangdep', - 'Go dep package manager', - ); - } catch (err) { - t.fail('expected to pass'); - } - }, - '`test composer-app --all-projects`': (params, utils) => async (t) => { - utils.chdirWorkspaces(); - const spyPlugin = sinon.spy(params.plugins, 'loadPlugin'); - t.teardown(spyPlugin.restore); - - const result: CommandResult = await params.cli.test('composer-app', { - allProjects: true, - }); - - t.ok(spyPlugin.withArgs('composer').calledOnce, 'calls composer plugin'); - - params.server.popRequests(2).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', 'posts to correct url'); - }); - t.match( - result.getDisplayResults(), - 'Package manager: composer', - 'contains package manager composer', - ); - t.match( - result.getDisplayResults(), - 'Target file: composer.lock', - 'contains target file composer.lock', - ); - }, - '`test mono-repo-go --all-projects --detection-depth=2`': ( - params, - utils, - ) => async (t) => { - utils.chdirWorkspaces(); - const mockPlugin = { - async inspect() { - return { - package: {}, - plugin: { - name: 'mock', - }, - }; - }, - }; - const loadPlugin = sinon.stub(params.plugins, 'loadPlugin'); - t.teardown(loadPlugin.restore); - // prevent plugin inspect from actually running (requires go to be installed) - loadPlugin.withArgs('golangdep').returns(mockPlugin); - loadPlugin.withArgs('gomodules').returns(mockPlugin); - loadPlugin.withArgs('govendor').returns(mockPlugin); - loadPlugin.callThrough(); // don't mock npm plugin - - const res: CommandResult = await params.cli.test('mono-repo-go', { - allProjects: true, - detectionDepth: 3, - }); - t.ok(loadPlugin.withArgs('golangdep').calledOnce, 'calls go dep plugin'); - t.ok(loadPlugin.withArgs('gomodules').calledOnce, 'calls go mod plugin'); - t.ok(loadPlugin.withArgs('npm').calledOnce, 'calls npm plugin'); - t.ok( - loadPlugin.withArgs('govendor').calledOnce, - 'calls go vendor plugin', + `Target file: src${path.sep}paymentservice${path.sep}package-lock.json`, + 'Npm project targetFile is as expected', ); t.match( res.getDisplayResults(), - /Tested 4 projects, no vulnerable paths were found./, - 'Four projects tested', + `Target file: src${path.sep}cocoapods-app${path.sep}Podfile`, + 'Cocoapods project targetFile is as expected', ); t.match( res.getDisplayResults(), - `Target file: hello-dep${path.sep}Gopkg.lock`, + `Target file: src${path.sep}frontend${path.sep}Gopkg.lock`, 'Go dep project targetFile is as expected', ); t.match( res.getDisplayResults(), - `Target file: hello-mod${path.sep}go.mod`, - 'Go mod project targetFile is as expected', + `Target file: src${path.sep}cartservice-nuget${path.sep}obj${path.sep}project.assets.json`, + 'Nuget project targetFile is as expected', ); t.match( res.getDisplayResults(), - `Target file: hello-node${path.sep}package-lock.json`, - 'Npm project targetFile is as expected', + `Target file: test${path.sep}nuget-app-4${path.sep}packages.config`, + 'Nuget project targetFile is as expected', ); t.match( res.getDisplayResults(), - `Target file: hello-vendor${path.sep}vendor${path.sep}vendor.json`, - 'Go vendor project targetFile is as expected', + `Target file: test${path.sep}paket-app${path.sep}paket.dependencies`, + 'Paket project targetFile is as expected', ); + t.match( res.getDisplayResults(), - 'Package manager: golangdep', + 'Package manager: nuget', 'Nuget package manager', ); t.match( res.getDisplayResults(), - 'Package manager: gomodules', - 'Nuget package manager', + 'Package manager: cocoapods', + 'Cocoapods package manager', ); t.match( res.getDisplayResults(), @@ -932,9 +818,123 @@ export const AllProjectsTests: AcceptanceTests = { ); t.match( res.getDisplayResults(), - 'Package manager: govendor', + 'Package manager: golangdep', 'Go dep package manager', ); - }, + } catch (err) { + t.fail('expected to pass'); + } + }, + '`test composer-app --all-projects`': (params, utils) => async (t) => { + utils.chdirWorkspaces(); + const spyPlugin = sinon.spy(params.plugins, 'loadPlugin'); + t.teardown(spyPlugin.restore); + + const result: CommandResult = await params.cli.test('composer-app', { + allProjects: true, + }); + + t.ok(spyPlugin.withArgs('composer').calledOnce, 'calls composer plugin'); + + params.server.popRequests(2).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', 'posts to correct url'); + }); + t.match( + result.getDisplayResults(), + 'Package manager: composer', + 'contains package manager composer', + ); + t.match( + result.getDisplayResults(), + 'Target file: composer.lock', + 'contains target file composer.lock', + ); + }, + '`test mono-repo-go --all-projects --detection-depth=2`': ( + params, + utils, + ) => async (t) => { + utils.chdirWorkspaces(); + const mockPlugin = { + async inspect() { + return { + package: {}, + plugin: { + name: 'mock', + }, + }; + }, + }; + const loadPlugin = sinon.stub(params.plugins, 'loadPlugin'); + t.teardown(loadPlugin.restore); + // prevent plugin inspect from actually running (requires go to be installed) + loadPlugin.withArgs('golangdep').returns(mockPlugin); + loadPlugin.withArgs('gomodules').returns(mockPlugin); + loadPlugin.withArgs('govendor').returns(mockPlugin); + loadPlugin.callThrough(); // don't mock npm plugin + + const res: CommandResult = await params.cli.test('mono-repo-go', { + allProjects: true, + detectionDepth: 3, + }); + t.ok(loadPlugin.withArgs('golangdep').calledOnce, 'calls go dep plugin'); + t.ok(loadPlugin.withArgs('gomodules').calledOnce, 'calls go mod plugin'); + t.ok(loadPlugin.withArgs('npm').calledOnce, 'calls npm plugin'); + t.ok( + loadPlugin.withArgs('govendor').calledOnce, + 'calls go vendor plugin', + ); + t.match( + res.getDisplayResults(), + /Tested 4 projects, no vulnerable paths were found./, + 'Four projects tested', + ); + t.match( + res.getDisplayResults(), + `Target file: hello-dep${path.sep}Gopkg.lock`, + 'Go dep project targetFile is as expected', + ); + t.match( + res.getDisplayResults(), + `Target file: hello-mod${path.sep}go.mod`, + 'Go mod project targetFile is as expected', + ); + t.match( + res.getDisplayResults(), + `Target file: hello-node${path.sep}package-lock.json`, + 'Npm project targetFile is as expected', + ); + t.match( + res.getDisplayResults(), + `Target file: hello-vendor${path.sep}vendor${path.sep}vendor.json`, + 'Go vendor project targetFile is as expected', + ); + t.match( + res.getDisplayResults(), + 'Package manager: golangdep', + 'Nuget package manager', + ); + t.match( + res.getDisplayResults(), + 'Package manager: gomodules', + 'Nuget package manager', + ); + t.match( + res.getDisplayResults(), + 'Package manager: npm', + 'Npm package manager', + ); + t.match( + res.getDisplayResults(), + 'Package manager: govendor', + 'Go dep package manager', + ); + }, }, }; diff --git a/test/acceptance/cli-test/cli-test.gradle.spec.ts b/test/acceptance/cli-test/cli-test.gradle.spec.ts index 323e3db499e..7713d8e38a0 100644 --- a/test/acceptance/cli-test/cli-test.gradle.spec.ts +++ b/test/acceptance/cli-test/cli-test.gradle.spec.ts @@ -112,6 +112,50 @@ export const GradleTests: AcceptanceTests = { }); t.true(((spyPlugin.args[0] as any)[2] as any).allSubProjects); }, + '`test gradle-app --all-sub-projects` with policy': ( + params, + utils, + ) => async (t) => { + utils.chdirWorkspaces(); + const plugin = { + async inspect() { + return { plugin: { name: 'gradle' }, package: {} }; + }, + }; + const spyPlugin = sinon.spy(plugin, 'inspect'); + const loadPlugin = sinon.stub(params.plugins, 'loadPlugin'); + t.teardown(loadPlugin.restore); + loadPlugin.withArgs('gradle').returns(plugin); + + await params.cli.test('gradle-app', { + allSubProjects: true, + }); + t.true(((spyPlugin.args[0] as any)[2] as any).allSubProjects); + const requests = params.server.popRequests(2); + let policyCount = 0; + requests.forEach((req) => { + if ( + req.body.displayTargetFile.endsWith('gradle-multi-project/subproj') + ) { + // TODO: this should return 1 policy when fixed + // uncomment then + // t.match( + // req.body.policy, + // 'SNYK-JAVA-ORGBOUNCYCASTLE-32364', + // 'policy is found & sent', + // ); + t.ok( + req.body.policy, + undefined, + 'policy is not found even though it should be', + ); + policyCount += 1; + } + t.match(req.url, '/test-dep-graph', 'posts to correct url'); + }); + // TODO: this should return 1 policy when fixed + t.equal(policyCount, 0, 'one sub-project policy found & sent'); + }, '`test gradle-app` plugin fails to return package or scannedProjects': ( params, diff --git a/test/acceptance/workspaces/gradle-multi-project/build.gradle b/test/acceptance/workspaces/gradle-multi-project/build.gradle new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/acceptance/workspaces/gradle-multi-project/settings.gradle b/test/acceptance/workspaces/gradle-multi-project/settings.gradle new file mode 100644 index 00000000000..90289e8a32b --- /dev/null +++ b/test/acceptance/workspaces/gradle-multi-project/settings.gradle @@ -0,0 +1,5 @@ +rootProject.name = 'root-proj' + +include 'subproj' + + diff --git a/test/acceptance/workspaces/gradle-multi-project/subproj/.snyk b/test/acceptance/workspaces/gradle-multi-project/subproj/.snyk new file mode 100644 index 00000000000..d46ea24efac --- /dev/null +++ b/test/acceptance/workspaces/gradle-multi-project/subproj/.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: + SNYK-JAVA-ORGBOUNCYCASTLE-32364: + - '*': + reason: None Given + expires: 2020-07-19T11:33:19.028Z +patch: {} diff --git a/test/acceptance/workspaces/gradle-multi-project/subproj/build.gradle b/test/acceptance/workspaces/gradle-multi-project/subproj/build.gradle new file mode 100644 index 00000000000..301e7be03bc --- /dev/null +++ b/test/acceptance/workspaces/gradle-multi-project/subproj/build.gradle @@ -0,0 +1,51 @@ +apply plugin: 'java' +apply plugin: 'maven' + +group = 'com.github.jitpack' + +sourceCompatibility = 1.8 // java 8 +targetCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + // Gradle 3+ will not pick up "compile" dependencies for "compileOnly" + // Gradle 2 will, so for configuration-matching tests we use "runtime" + runtime 'com.google.guava:guava:18.0' + runtime 'batik:batik-dom:1.6' + runtime 'commons-discovery:commons-discovery:0.2' + compileOnly 'axis:axis:1.3' + runtime 'com.android.tools.build:builder:2.3.0' +} + +task sourcesJar(type: Jar, dependsOn: classes) { + classifier = 'sources' + from sourceSets.main.allSource +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = 'javadoc' + from javadoc.destinationDir +} + +artifacts { + archives sourcesJar + archives javadocJar +} + +// To specify a license in the pom: +install { + repositories.mavenInstaller { + pom.project { + licenses { + license { + name 'The Apache Software License, Version 2.0' + url 'http://www.apache.org/licenses/LICENSE-2.0.txt' + distribution 'repo' + } + } + } + } +}