Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add go dep, vendor and mod to auto detect #977

Merged
merged 1 commit into from
Jan 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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