Skip to content

Commit

Permalink
feat: add reachable vulnerabilities support for gradle
Browse files Browse the repository at this point in the history
  • Loading branch information
Mila Votradovec authored and Dar Malovani committed Sep 29, 2020
1 parent 50ab9b0 commit a0e7460
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 7 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
"snyk-cpp-plugin": "2.0.0",
"snyk-docker-plugin": "3.24.0",
"snyk-go-plugin": "1.16.2",
"snyk-gradle-plugin": "3.6.3",
"snyk-gradle-plugin": "3.7.0",
"snyk-module": "3.1.0",
"snyk-mvn-plugin": "2.19.4",
"snyk-nodejs-lockfile-parser": "1.28.1",
Expand Down
38 changes: 38 additions & 0 deletions src/lib/monitor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,43 @@ export async function monitorDepGraph(
// this graph will be pruned only if is too dense
depGraph = await pruneGraph(depGraph, packageManager);

let callGraphPayload;
if (
options.reachableVulns &&
(scannedProject.callGraph as CallGraphError)?.innerError
) {
const err = scannedProject.callGraph as CallGraphError;
analytics.add(
'callGraphError',
abridgeErrorMessage(
err.innerError.toString(),
ANALYTICS_PAYLOAD_MAX_LENGTH,
),
);
alerts.registerAlerts([
{
type: 'error',
name: 'missing-call-graph',
msg: err.message,
},
]);
} else if (scannedProject.callGraph) {
const { callGraph, nodeCount, edgeCount } = serializeCallGraphWithMetrics(
scannedProject.callGraph as CallGraph,
);
debug(
`Adding call graph to payload, node count: ${nodeCount}, edge count: ${edgeCount}`,
);

const callGraphMetrics = _.get(pluginMeta, 'meta.callGraphMetrics', {});
analytics.add('callGraphMetrics', {
callGraphEdgeCount: edgeCount,
callGraphNodeCount: nodeCount,
...callGraphMetrics,
});
callGraphPayload = callGraph;
}

return new Promise((resolve, reject) => {
if (!depGraph) {
debug(
Expand Down Expand Up @@ -432,6 +469,7 @@ export async function monitorDepGraph(
targetFile: getTargetFile(scannedProject, pluginMeta),
targetFileRelativePath,
contributors,
callGraph: callGraphPayload,
} as MonitorBody,
gzip: true,
method: 'PUT',
Expand Down
1 change: 1 addition & 0 deletions src/lib/package-managers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@ export const PINNING_SUPPORTED_PACKAGE_MANAGERS: SupportedPackageManagers[] = [
];
export const REACHABLE_VULNS_SUPPORTED_PACKAGE_MANAGERS: SupportedPackageManagers[] = [
'maven',
'gradle',
];
6 changes: 3 additions & 3 deletions test/acceptance/cli-reachable-vulns.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ before('prime config', async (t) => {

test('test vulnerable project with --reachable-vulns not supported package manager', async (t) => {
try {
await cli.test('gradle', {
await cli.test('npm-package', {
reachableVulns: true,
});
t.fail('expected test to throw exception');
Expand All @@ -66,13 +66,13 @@ test('monitor vulnerable project with --reachable-vulns not supported package ma
try {
await cli.monitor('.', {
reachableVulns: true,
packageManager: 'gradle',
packageManager: 'npm',
});
t.fail('expected test to throw exception');
} catch (err) {
t.match(
err.message,
`'Reachable vulns' is not supported for package manager 'gradle'. For a list of supported package managers go to https://support.snyk.io/hc/en-us/articles/360010554837-Reachable-Vulnerabilities`,
`'Reachable vulns' is not supported for package manager 'npm'. For a list of supported package managers go to https://support.snyk.io/hc/en-us/articles/360010554837-Reachable-Vulnerabilities`,
);
}
});
Expand Down
59 changes: 59 additions & 0 deletions test/acceptance/cli-test/cli-test.gradle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as sinon from 'sinon';
import { legacyPlugin as pluginApi } from '@snyk/cli-interface';
import { AcceptanceTests } from './cli-test.acceptance.test';
import { CommandResult } from '../../../src/cli/commands/types';
import { createCallGraph } from '../../utils';

export const GradleTests: AcceptanceTests = {
language: 'Gradle',
Expand Down Expand Up @@ -92,6 +93,64 @@ export const GradleTests: AcceptanceTests = {
);
},

'`test gradle-app --reachable-vulns` sends call graph': (
params,
utils,
) => async (t) => {
utils.chdirWorkspaces();
const callGraphPayload = require('../fixtures/call-graphs/maven.json');
const callGraph = createCallGraph(callGraphPayload);
const plugin = {
async inspect() {
return {
package: {},
plugin: { name: 'testplugin', runtime: 'testruntime' },
callGraph,
};
},
};
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', {
reachableVulns: true,
});
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');
t.equal(req.body.depGraph.pkgManager.name, 'gradle');
t.deepEqual(
req.body.callGraph,
callGraphPayload,
'correct call graph sent',
);
t.same(
spyPlugin.getCall(0).args,
[
'gradle-app',
'build.gradle',
{
args: null,
file: 'build.gradle',
org: null,
projectName: null,
packageManager: 'gradle',
path: 'gradle-app',
showVulnPaths: 'some',
reachableVulns: true,
},
],
'calls gradle plugin',
);
},

'`test gradle-app --all-sub-projects` sends `allSubProjects` argument to plugin': (
params,
utils,
Expand Down
10 changes: 7 additions & 3 deletions test/reachable-vulns.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from '../src/lib/reachable-vulns';
import {
SUPPORTED_PACKAGE_MANAGER_NAME,
REACHABLE_VULNS_SUPPORTED_PACKAGE_MANAGERS,
SupportedPackageManagers,
} from '../src/lib/package-managers';
import * as featureFlags from '../src/lib/feature-flags';
Expand Down Expand Up @@ -166,9 +167,12 @@ test('formatReachablePaths', (t) => {
});

test('validatePayload - not supported package manager', async (t) => {
const pkgManagers = Object.keys(SUPPORTED_PACKAGE_MANAGER_NAME);
const mavenIndex = pkgManagers.indexOf('maven');
pkgManagers.splice(mavenIndex, 1); // remove maven as it's supported
const pkgManagers = Object.keys(SUPPORTED_PACKAGE_MANAGER_NAME).filter(
(name) =>
!REACHABLE_VULNS_SUPPORTED_PACKAGE_MANAGERS.includes(
name as SupportedPackageManagers,
),
);
t.plan(pkgManagers.length * 3);

for (const pkgManager of pkgManagers) {
Expand Down

0 comments on commit a0e7460

Please sign in to comment.