Skip to content

Commit

Permalink
Merge pull request #977 from snyk/feat/auto-detect-golang
Browse files Browse the repository at this point in the history
feat: add go dep, vendor and mod to auto detect
  • Loading branch information
gitphill committed Jan 28, 2020
2 parents 0bbeda5 + 65e0a76 commit ff2ee39
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
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
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
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
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
@@ -0,0 +1 @@
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=

0 comments on commit ff2ee39

Please sign in to comment.