Skip to content

Commit

Permalink
feat: add go dep, vendor and mod to auto detect
Browse files Browse the repository at this point in the history
Add support for auto detecting go dep, vendor and module projects
when using --all-projects arg.
  • Loading branch information
gitphill committed Jan 28, 2020
1 parent 96de91d commit 65e0a76
Show file tree
Hide file tree
Showing 38 changed files with 4,520 additions and 28 deletions.
3 changes: 3 additions & 0 deletions src/lib/detect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ export const AUTO_DETECTABLE_FILES: string[] = [
'Podfile',
'Podfile.lock',
'composer.lock',
'Gopkg.lock',
'go.mod',
'vendor.json',
];

// when file is specified with --file, we look it up here
Expand Down
170 changes: 160 additions & 10 deletions test/acceptance/cli-monitor/cli-monitor.all-projects.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface AcceptanceTests {
}

export const AllProjectsTests: AcceptanceTests = {
language: 'Mixed (Ruby & Npm & Maven)',
language: 'Mixed',
tests: {
'`monitor mono-repo-project with lockfiles --all-projects`': (
params,
Expand Down Expand Up @@ -309,24 +309,174 @@ export const AllProjectsTests: AcceptanceTests = {
await params.cli.monitor('monorepo-with-nuget/src/cocoapods-app', {
allProjects: true,
});
// Pop all calls to server and filter out calls to `featureFlag` endpoint
const [cocoapodsAll] = params.server
.popRequests(1)
.filter((req) => req.url.includes('/monitor/'));

const cocoapodsAll = params.server.popRequest();
// Cocoapods
await params.cli.monitor('monorepo-with-nuget/src/cocoapods-app', {
file: 'Podfile',
});
const [requestsCocoapods] = params.server
.popRequests(1)
.filter((req) => req.url.includes('/monitor/'));

const requestsCocoapods = params.server.popRequest();
t.deepEqual(
cocoapodsAll.body,
requestsCocoapods.body,
'Same body for --all-projects and --file=src/cocoapods-app/Podfile',
);
},
'`monitor mono-repo-go/hello-dep --all-projects sends same body as --file`': (
params,
utils,
) => async (t) => {
utils.chdirWorkspaces();
// mock plugin becuase CI tooling doesn't have go installed
const mockPlugin = {
async inspect() {
return {
plugin: {
targetFile: 'Gopkg.lock',
name: 'snyk-go-plugin',
runtime: 'go',
},
package: {},
};
},
};
const loadPlugin = sinon.stub(params.plugins, 'loadPlugin');
t.teardown(loadPlugin.restore);
loadPlugin.withArgs('golangdep').returns(mockPlugin);
await params.cli.monitor('mono-repo-go/hello-dep', {
allProjects: true,
});
const allProjectsBody = params.server.popRequest();
await params.cli.monitor('mono-repo-go/hello-dep', {
file: 'Gopkg.lock',
});
const fileBody = params.server.popRequest();
t.same(
allProjectsBody.body,
fileBody.body,
'Same body for --all-projects and --file=mono-repo-go/hello-dep/Gopkg.lock',
);
},
'`monitor mono-repo-go/hello-mod --all-projects sends same body as --file`': (
params,
utils,
) => async (t) => {
utils.chdirWorkspaces();
// mock plugin becuase CI tooling doesn't have go installed
const mockPlugin = {
async inspect() {
return {
plugin: {
targetFile: 'go.mod',
name: 'snyk-go-plugin',
runtime: 'go',
},
package: {},
};
},
};
const loadPlugin = sinon.stub(params.plugins, 'loadPlugin');
t.teardown(loadPlugin.restore);
loadPlugin.withArgs('gomodules').returns(mockPlugin);
await params.cli.monitor('mono-repo-go/hello-mod', {
allProjects: true,
});
const allProjectsBody = params.server.popRequest();
await params.cli.monitor('mono-repo-go/hello-mod', {
file: 'go.mod',
});
const fileBody = params.server.popRequest();
t.same(
allProjectsBody.body,
fileBody.body,
'Same body for --all-projects and --file=mono-repo-go/hello-mod/go.mod',
);
},
'`monitor mono-repo-go/hello-vendor --all-projects sends same body as --file`': (
params,
utils,
) => async (t) => {
utils.chdirWorkspaces();
// mock plugin becuase CI tooling doesn't have go installed
const mockPlugin = {
async inspect() {
return {
plugin: {
targetFile: 'vendor/vendor.json',
name: 'snyk-go-plugin',
runtime: 'go',
},
package: {},
};
},
};
const loadPlugin = sinon.stub(params.plugins, 'loadPlugin');
t.teardown(loadPlugin.restore);
loadPlugin.withArgs('govendor').returns(mockPlugin);
await params.cli.monitor('mono-repo-go/hello-vendor', {
allProjects: true,
});
const allProjectsBody = params.server.popRequest();
await params.cli.monitor('mono-repo-go/hello-vendor', {
file: 'vendor/vendor.json',
});
const fileBody = params.server.popRequest();
t.same(
allProjectsBody.body,
fileBody.body,
'Same body for --all-projects and --file=mono-repo-go/hello-vendor/vendor/vendor.json',
);
},

'`monitor mono-repo-go with --all-projects and --detectin-depth=3`': (
params,
utils,
) => async (t) => {
utils.chdirWorkspaces();
// mock plugin becuase CI tooling doesn't have go installed
const mockPlugin = {
async inspect() {
return {
plugin: {
name: 'mock',
},
package: {},
};
},
};
const loadPlugin = sinon.stub(params.plugins, 'loadPlugin');
t.teardown(loadPlugin.restore);
loadPlugin.withArgs('golangdep').returns(mockPlugin);
loadPlugin.withArgs('gomodules').returns(mockPlugin);
loadPlugin.withArgs('npm').returns(mockPlugin);
loadPlugin.withArgs('govendor').returns(mockPlugin);
const result = await params.cli.monitor('mono-repo-go', {
allProjects: true,
detectionDepth: 3,
});
t.match(result, 'golangdep/some/project-id', 'dep project was monitored');
t.match(result, 'gomodules/some/project-id', 'mod project was monitored');
t.match(result, 'npm/graph/some/project-id', 'npm project was monitored');
t.match(
result,
'govendor/some/project-id',
'vendor project was monitored',
);
// Pop one extra call to server and filter out call to `featureFlag` endpoint
const requests = params.server
.popRequests(5)
.filter((req) => req.url.includes('/monitor/'));
t.equal(requests.length, 4, 'Correct amount of monitor requests');

requests.forEach((req) => {
t.match(req.url, '/monitor/', 'puts at correct url');
t.notOk(req.body.targetFile, "doesn't send the targetFile");
t.equal(req.method, 'PUT', 'makes PUT request');
t.equal(
req.headers['x-snyk-cli-version'],
params.versionNumber,
'sends version number',
);
});
},
},
};
127 changes: 112 additions & 15 deletions test/acceptance/cli-test/cli-test.all-projects.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as path from 'path';
import * as sinon from 'sinon';

export const AllProjectsTests: AcceptanceTests = {
language: 'Mixed (Ruby & Npm & Maven)',
language: 'Mixed',
tests: {
'`test mono-repo-project with lockfiles --all-projects`': (
params,
Expand Down Expand Up @@ -383,37 +383,69 @@ export const AllProjectsTests: AcceptanceTests = {
);
}
},
'`test monorepo --all-projects with Nuget, Python, Go, Npm`': (

'`test monorepo-with-nuget --all-projects with Nuget, Python, Go, Npm, Cocoapods`': (
params,
utils,
) => async (t) => {
utils.chdirWorkspaces();
const spyPlugin = sinon.spy(params.plugins, 'loadPlugin');
t.teardown(spyPlugin.restore);
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('nuget').returns(mockPlugin);
loadPlugin.withArgs('cocoapods').returns(mockPlugin);
loadPlugin.withArgs('npm').returns(mockPlugin);
loadPlugin.withArgs('golangdep').returns(mockPlugin);

try {
const res = await params.cli.test('monorepo-with-nuget', {
allProjects: true,
detectionDepth: 4,
});
t.equal(
loadPlugin.withArgs('nuget').callCount,
2,
'calls nuget plugin twice',
);
t.ok(
spyPlugin.withArgs('cocoapods').callCount,
1,
loadPlugin.withArgs('cocoapods').calledOnce,
'calls cocoapods plugin',
);
t.ok(spyPlugin.withArgs('nuget').callCount, 2, 'calls nuget plugin');
t.ok(spyPlugin.withArgs('npm').calledOnce, 'calls npm plugin');
t.ok(loadPlugin.withArgs('npm').calledOnce, 'calls npm plugin');
t.ok(
loadPlugin.withArgs('golangdep').calledOnce,
'calls golangdep plugin',
);
t.match(
res,
/Tested 4 projects, no vulnerable paths were found./,
'Two projects tested',
/Tested 5 projects, no vulnerable paths were found./,
'Five projects tested',
);
t.match(
res,
`Target file: src${path.sep}paymentservice${path.sep}package-lock.json`,
'Npm project targetFile is as expected',
);
t.match(res, 'Package manager: npm', 'Npm package manager');
t.match(
res,
`Target file: src${path.sep}cocoapods-app${path.sep}Podfile`,
'Cocoapods project targetFile is as expected',
);
t.match(
res,
`Target file: src${path.sep}frontend${path.sep}Gopkg.lock`,
'Go dep project targetFile is as expected',
);
t.match(
res,
`Target file: src${path.sep}cartservice-nuget${path.sep}obj${path.sep}project.assets.json`,
Expand All @@ -425,16 +457,17 @@ export const AllProjectsTests: AcceptanceTests = {
'Nuget project targetFile is as expected',
);
t.match(res, 'Package manager: nuget', 'Nuget package manager');

t.match(
res,
`Target file: src${path.sep}cocoapods-app${path.sep}Podfile`,
'Cocoapods project targetFile is as expected',
'Package manager: cocoapods',
'Cocoapods package manager',
);
t.match(res, 'Package manager: npm', 'Npm package manager');
t.match(res, 'Package manager: golangdep', 'Go dep package manager');
t.match(
res,
'Package manager: cocoapods',
'cocoapods package manager',
'Cocoapods package manager',
);
} catch (err) {
t.fail('expected to pass');
Expand Down Expand Up @@ -471,5 +504,69 @@ export const AllProjectsTests: AcceptanceTests = {
'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('npm').returns(mockPlugin);
loadPlugin.withArgs('govendor').returns(mockPlugin);

const res = 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,
/Tested 4 projects, no vulnerable paths were found./,
'Four projects tested',
);
t.match(
res,
`Target file: hello-dep${path.sep}Gopkg.lock`,
'Go dep project targetFile is as expected',
);
t.match(
res,
`Target file: hello-mod${path.sep}go.mod`,
'Go mod project targetFile is as expected',
);
t.match(
res,
`Target file: hello-node${path.sep}package-lock.json`,
'Npm project targetFile is as expected',
);
t.match(
res,
`Target file: hello-vendor${path.sep}vendor${path.sep}vendor.json`,
'Go vendor project targetFile is as expected',
);
t.match(res, 'Package manager: golangdep', 'Nuget package manager');
t.match(res, 'Package manager: gomodules', 'Nuget package manager');
t.match(res, 'Package manager: npm', 'Npm package manager');
t.match(res, 'Package manager: govendor', 'Go dep package manager');
},
},
};
4 changes: 1 addition & 3 deletions test/acceptance/workspaces/golang-gomodules/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,4 @@ module app

go 1.12

require (
github.com/lib/pq v1.1.1
)
require github.com/lib/pq v1.1.1
1 change: 1 addition & 0 deletions test/acceptance/workspaces/golang-gomodules/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
Loading

0 comments on commit 65e0a76

Please sign in to comment.