Skip to content

Commit

Permalink
feat: send target data on monitor to registry
Browse files Browse the repository at this point in the history
  • Loading branch information
odinn1984 committed May 7, 2019
1 parent cc7d9fe commit 868a907
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 4 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"configstore": "^3.1.2",
"debug": "^3.1.0",
"diff": "^4.0.1",
"git-url-parse": "11.1.2",
"glob": "^7.1.3",
"inquirer": "^6.2.2",
"lodash": "^4.17.11",
Expand Down
3 changes: 1 addition & 2 deletions src/cli/commands/monitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ async function monitor(...args0: any[]): Promise<any> {
if (options['all-sub-projects'] && options['project-name']) {
throw new Error('`--all-sub-projects` is currently not compatible with `--project-name`');
}

await apiTokenExists('snyk monitor');
// Part 1: every argument is a scan target; process them sequentially
for (const path of args) {
Expand Down Expand Up @@ -153,7 +152,7 @@ async function monitor(...args0: any[]): Promise<any> {
// Post the project dependencies to the Registry
for (const depRootDeps of perDepRootResults) {
const res = await promiseOrCleanup(
snykMonitor(path, meta, depRootDeps),
snykMonitor(path, meta, depRootDeps, targetFile),
spinner.clear(postingMonitorSpinnerLabel));

await spinner.clear(postingMonitorSpinnerLabel)(res);
Expand Down
14 changes: 12 additions & 2 deletions src/lib/monitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ import * as _ from 'lodash';
import * as isCI from './is-ci';
import * as analytics from './analytics';
import { SingleDepRootResult, MonitorError } from './types';
import * as projectMetadata from './project-metadata';
import * as path from 'path';

// TODO(kyegupov): clean up the type, move to snyk-cli-interface repository

interface MonitorBody {
meta: Meta;
policy: string;
package: {}; // TODO(kyegupov): DepTree
target: {};
targetFileRelativePath: string;
targetFile: string;
}

Expand All @@ -35,7 +39,7 @@ interface Meta {
projectName: string;
}

export function monitor(root, meta, info: SingleDepRootResult): Promise<any> {
export function monitor(root, meta, info: SingleDepRootResult, targetFile): Promise<any> {
const pkg = info.package;
const pluginMeta = info.plugin;
let policyPath = meta['policy-path'];
Expand All @@ -52,8 +56,12 @@ export function monitor(root, meta, info: SingleDepRootResult): Promise<any> {
return snyk.policy.create();
}
return snyk.policy.load(policyLocations, opts);
}).then((policy) => {
}).then(async (policy) => {
analytics.add('packageManager', packageManager);

const target = await projectMetadata.getInfo(pkg);
const targetFileRelativePath = targetFile ? path.relative(root, targetFile) : '';

// TODO(kyegupov): async/await
return new Promise((resolve, reject) => {
request({
Expand All @@ -79,7 +87,9 @@ export function monitor(root, meta, info: SingleDepRootResult): Promise<any> {
package: pkg,
// we take the targetFile from the plugin,
// because we want to send it only for specific package-managers
target,
targetFile: pluginMeta.targetFile,
targetFileRelativePath,
} as MonitorBody,
gzip: true,
method: 'PUT',
Expand Down
18 changes: 18 additions & 0 deletions src/lib/project-metadata/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as gitTargetBuilder from './target-builders/git';
import { GitTarget } from './types';

const TARGET_BUILDERS = [
gitTargetBuilder,
];

export async function getInfo(packageInfo): Promise<GitTarget|null> {
for (const builder of TARGET_BUILDERS) {
const target = await builder.getInfo(packageInfo);

if (target) {
return target;
}
}

return null;
}
33 changes: 33 additions & 0 deletions src/lib/project-metadata/target-builders/git.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import fs = require('fs');
import GitUrlParse = require('git-url-parse');

import subProcess = require('../../sub-process');
import { GitTarget } from '../types';

export async function getInfo(packageInfo): Promise<GitTarget|null> {
let origin: string|null|undefined;

if (packageInfo.docker) {
return null;
}

try {
origin = (await subProcess.execute('git', ['remote', 'get-url', 'origin'])).trim();

if (!origin) {
return null;
}

const parsedOrigin = GitUrlParse(origin);
const branch = (await subProcess.execute('git', ['rev-parse', '--abbrev-ref', 'HEAD'])).trim();

return {
remoteUrl: parsedOrigin.toString('http'),
branch,
};
} catch (err) {
// Swallowing exception since we don't want to break the monitor if there is a problem
// executing git commands.
return null;
}
}
4 changes: 4 additions & 0 deletions src/lib/project-metadata/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface GitTarget {
remoteUrl: string;
branch: string;
}
73 changes: 73 additions & 0 deletions test/monitor-target.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
'use strict';

const test = require('tape').test;
const zlib = require('zlib');
const requestLib = require('needle');

import * as _ from 'lodash';
import * as sinon from 'sinon';

import * as cli from '../src/cli/commands';
import subProcess = require('../src/lib/sub-process');

test('Make sure that target is sent correctly', async (t) => {
const subProcessStub = sinon.stub(subProcess, 'execute');

subProcessStub.withArgs('git', ['remote', 'get-url', 'origin'])
.resolves('http://github.com/snyk/project.git');

subProcessStub.withArgs('git', ['rev-parse', '--abbrev-ref', 'HEAD'])
.resolves('master');

const { data, spy } = await getMonitorRequestDataAndSpy();

t.true(spy.calledOnce, 'needle.request was called once');
t.true(!_.isEmpty(data.target), 'target passed to request');
t.true(!_.isEmpty(data.targetFileRelativePath), 'targetFileRelativePath passed to request');
t.equals(data.target.branch, 'master', 'correct branch passed to request');
t.equals(data.target.remoteUrl, 'http://github.com/snyk/project.git', 'correct name passed to request');
t.equals(data.targetFileRelativePath, 'package.json', 'correct relative target file path passed to request');

subProcessStub.restore();
spy.restore();
t.end();
});

test('Make sure it\'s not failing monitor for non git projects', async (t) => {
const subProcessStub = sinon.stub(subProcess, 'execute').resolves('');
const { data, spy } = await getMonitorRequestDataAndSpy();

t.true(spy.calledOnce, 'needle.request was called once');
t.true(_.isEmpty(data.target), 'empty target passed to request');
t.equals(data.targetFileRelativePath, 'package.json', 'targetFileRelativePath passed to request');

subProcessStub.restore();
spy.restore();
t.end();
});

test('Make sure it\'s not failing if there is no remote configured', async (t) => {
const subProcessStub = sinon.stub(subProcess, 'execute').rejects();
const { data, spy } = await getMonitorRequestDataAndSpy();

t.true(spy.calledOnce, 'needle.request was called once');
t.true(_.isEmpty(data.target), 'empty target passed to request');
t.equals(data.targetFileRelativePath, 'package.json', 'targetFileRelativePath passed to request');

subProcessStub.restore();
spy.restore();
t.end();
});

async function getMonitorRequestDataAndSpy() {
const requestSpy = sinon.spy(requestLib, 'request');

await cli.monitor();

const data = JSON.parse(zlib.gunzipSync(requestSpy.getCall(0).args[2]).toString());

return {
data,
spy: requestSpy,
};
}

0 comments on commit 868a907

Please sign in to comment.