New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

snyk

Package Overview
Dependencies
Maintainers
2
Versions
1967
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

snyk - npm Package Compare versions

Comparing version 1.5.1 to 1.6.0-alpha1

.nyc_output/5205.json

2

cli/args.js

@@ -88,2 +88,4 @@ module.exports = args;

command === 'test' ||
command === 'modules' ||
command === 'scenario' ||
command === 'wizard') {

@@ -90,0 +92,0 @@ // copy all the options across to argv._ as an object

3

cli/commands/index.js

@@ -19,5 +19,6 @@ var abbrev = require('abbrev');

wizard: hotload('./protect/wizard'),
// modules: hotload('./modules'),
modules: hotload('./modules'),
scenario: hotload('./scenario'),
};
commands.aliases = abbrev(Object.keys(commands));
module.exports = commands;
var snyk = require('../../lib');
var Promise = require('es6-promise').Promise; // jshint ignore:line
module.exports = function (path) {
module.exports = function (path, options) {
return snyk.modules(path || process.cwd()).then(function (modules) {

@@ -12,2 +12,6 @@

if (options.json) {
return JSON.stringify(modules, '', 2);
}
return parent + Object.keys(modules.dependencies).map(function (key) {

@@ -14,0 +18,0 @@ return modules.dependencies[key].full;

@@ -8,4 +8,6 @@ module.exports = {

var _ = require('lodash');
var semver = require('semver');
var debug = require('debug')('snyk');
var protect = require('../../../lib/protect');
var moduleToObject = require('snyk-module');
var undefsafe = require('undefsafe');

@@ -15,3 +17,220 @@ var config = require('../../../lib/config');

// via http://stackoverflow.com/a/4760279/22617
function sort(prop) {
var sortOrder = 1;
if (prop[0] === '-') {
sortOrder = -1;
prop = prop.substr(1);
}
return function (a, b) {
var result = (a[prop] < b[prop]) ? -1 : (a[prop] > b[prop]) ? 1 : 0;
return result * sortOrder;
};
}
function sortPrompts(a, b) {
var res = 0;
// first sort by module affected
var pa = moduleToObject(a.from[1]);
var pb = moduleToObject(b.from[1]);
res = sort('name')(pa, pb);
if (res !== 0) {
return res;
}
// we should have the same module, so the depth should be the same
debug('sorting by upgradePath', a.upgradePath[1], b.upgradePath[1]);
if (a.upgradePath[1] && b.upgradePath[1]) {
// put upgrades ahead of patches
if (b.upgradePath[1] === false) {
return 1;
}
var pua = moduleToObject(a.upgradePath[1]);
var pub = moduleToObject(b.upgradePath[1]);
debug('%s > %s', pua.version, pub.version);
res = semver.compare(pua.version, pub.version) * -1;
if (res !== 0) {
return res;
}
} else {
if (a.upgradePath[1]) {
return -1;
}
if (b.upgradePath[1]) {
return 1;
}
}
// // sort by patch date
// if (a.patches.length) {
// // .slice because sort mutates
// var pda = a.patches.slice(0).sort(function (a, b) {
// return a.modificationTime - b.modificationTime;
// }).pop();
// var pdb = (b.patches || []).slice(0).sort(function (a, b) {
// return a.modificationTime - b.modificationTime;
// }).pop();
// if (pda && pdb) {
// return pda.modificationTime < pdb.modificationTime ? 1 :
// pda.modificationTime > pdb.modificationTime ? -1 : 0;
// }
// }
return res;
}
function getPrompts(vulns, policy) {
// take a copy so as not to mess with the original data
var res = _.cloneDeep(vulns);
// strip the irrelevant patches from the vulns at the same time, collect
// the unique package vulns
res = res.map(function (vuln) {
if (vuln.patches) {
vuln.patches = vuln.patches.filter(function (patch) {
return semver.satisfies(vuln.version, patch.version);
});
// sort by patchModification, then pick the latest one
vuln.patches = vuln.patches.sort(function (a, b) {
return b.modificationTime < a.modificationTime ? -1 : 1;
}).slice(0, 1);
// FIXME hack to give all the patches IDs if they don't already
if (vuln.patches[0] && !vuln.patches[0].id) {
vuln.patches[0].id = vuln.patches[0].urls[0].split('/').slice(-1).pop();
}
}
return vuln;
});
// sort by vulnerable package and the largest version
res.sort(sortPrompts);
var copy = null;
var offset = 0;
// mutate our objects so we can try to group them
// note that I use slice first becuase the `res` array will change length
// and `reduce` _really_ doesn't like when you change the array under
// it's feet
res.slice(0).reduce(function (acc, curr, i) {
var from = curr.from[1];
if (!acc[from]) {
// only copy the biggest change
copy = _.cloneDeep(curr);
acc[from] = curr;
return acc;
}
if (!acc[from].grouped) {
acc[from].grouped = {
affected: moduleToObject(from),
main: true,
id: acc[from].id + '-' + i,
count: 1,
upgrades: [],
};
acc[from].grouped.affected.full = from;
// splice this vuln into the list again so if the user choses to review
// they'll get this individual vuln and remediation
copy.grouped = {
main: false,
requires: acc[from].grouped.id,
};
res.splice(i + offset, 0, copy);
offset++;
}
debug('vuln found on group');
acc[from].grouped.count++;
curr.grouped = {
main: false,
requires: acc[from].grouped.id,
};
var upgrades = curr.upgradePath.slice(-1).shift();
debug('upgrade available? %s', upgrades && curr.upgradePath[1]);
// otherwise it's a patch and that's hidden for now
if (upgrades && curr.upgradePath[1]) {
var p = moduleToObject(upgrades);
if (p.name !== acc[from].grouped.affected.name &&
(' ' + acc[from].grouped.upgrades.join(' ') + ' ')
.indexOf(p.name + '@') === -1) {
debug('+ adding %s to upgrades', upgrades);
acc[from].grouped.upgrades.push(upgrades);
}
}
return acc;
}, {});
// now filter out any vulns that don't have an upgrade path and only patches
// and have already been grouped
var dropped = [];
res = res.filter(function (vuln) {
if (vuln.grouped) {
if (vuln.grouped.main) {
if (vuln.grouped.upgrades.length === 0) {
debug('dropping %s', vuln.grouped.id);
dropped.push(vuln.grouped.id);
return false;
}
}
// we have to remove the group property on the collective vulns if the
// top grouping has been removed, because otherwise they won't be shown
if (dropped.indexOf(vuln.grouped.requires) !== -1) {
delete vuln.grouped;
}
}
return true;
});
// resort after we made changes
res.sort(function (a) {
if (a.grouped) {
return -1;
}
if (a.upgradePath[1]) {
return -1;
}
return 1;
});
debug(res.map(function (v) {
return v.upgradePath[1];
}));
// console.log(JSON.stringify(res.map(function (vuln) {
// return vuln;
// return {
// from: vuln.from.slice(1).filter(Boolean).shift(),
// upgrade: (vuln.grouped || {}).upgrades,
// group: vuln.grouped
// };
// }), '', 2));
var prompts = generatePrompt(res, policy);
// do stuff
return prompts;
}
function generatePrompt(vulns, policy) {
if (!vulns) {

@@ -62,2 +281,7 @@ vulns = []; // being defensive, but maybe we should throw an error?

var update = _.cloneDeep(updateAction);
var review = {
value: 'review',
short: 'Review',
name: 'Review vulnerabilities separately',
};

@@ -69,12 +293,54 @@ var choices = [];

var severity = vuln.severity[0].toUpperCase() + vuln.severity.slice(1);
var infoLink = '- info: ' + config.ROOT;
var messageIntro;
var group = vuln.grouped && vuln.grouped.main ? vuln.grouped : false;
if (group) {
infoLink += '/package/npm/' + group.affected.name + '/' +
group.affected.version;
messageIntro = group.count + ' vulnerabilities introduced via ' +
group.affected.full;
} else {
infoLink += '/vuln/' + vuln.id;
messageIntro = severity + ' severity vulnerability found in ' + vulnIn +
', introduced via ' + from + (from !== vuln.from.slice(1).join(' > ') ?
'\n- from: ' + vuln.from.slice(1).join(' > ') : '');
}
var res = {
when: function () {
console.log(''); // blank line between prompts...kinda lame, sorry
return true;
when: function (answers) {
var res = true;
// console.log(answers);
// only show this question if the user chose to review the details
// of the vuln
if (vuln.grouped && !vuln.grouped.main) {
// find how they answered on the top level question
var groupAnswer = Object.keys(answers).map(function (key) {
if (answers[key].meta) {
if (answers[key].meta.groupId === vuln.grouped.requires) {
return answers[key];
}
}
return false;
}).filter(Boolean);
if (!groupAnswer.length) {
return false;
}
// if we've upgraded, then stop asking
res = groupAnswer.filter(function (answer) {
return answer.choice === 'update';
}).length === 0;
}
if (res) {
console.log(''); // blank line between prompts...kinda lame, sorry
}
return res; // true = show next
},
name: id,
type: 'list',
message: severity + ' severity vulnerability found in ' + vulnIn +
'\n - info: ' + config.ROOT + '/vuln/' + vuln.id +
'\n - from: ' + vuln.from.join(' > ')
message: [messageIntro, infoLink, ' Remediation options'].join('\n')
};

@@ -104,3 +370,14 @@

choices.push(update);
update.name = 'Upgrade to ' + vuln.upgradePath.filter(Boolean).shift();
var toPackage = vuln.upgradePath.filter(Boolean).shift();
update.short = 'Upgrade to ' + toPackage;
var out = 'Upgrade to ' + toPackage;
if (group) {
out += ' (triggers upgrade to ' + group.upgrades.join(', ') + ')';
} else {
var last = vuln.upgradePath.slice(-1).shift();
if (toPackage !== last) {
out += ' (triggers upgrade to ' + last + ')';
}
}
update.name = out;
} else {

@@ -117,31 +394,38 @@ // No upgrade available (as per no patch)

var patches = null;
if (vuln.patches && vuln.patches.length) {
// check that the version we have has a patch available
patches = protect.patchesForPackage({
name: vuln.name,
version: vuln.version,
}, vuln);
if (patches !== null) {
debug('%s@%s', vuln.name, vuln.version, patches);
if (!upgradeAvailable) {
patch.default = true;
if (group && group.upgrades.length) {
review.meta = {
groupId: group.id,
};
choices.push(review);
} else {
if (vuln.patches && vuln.patches.length) {
// check that the version we have has a patch available
patches = protect.patchesForPackage({
name: vuln.name,
version: vuln.version,
}, vuln);
if (patches !== null) {
if (!upgradeAvailable) {
patch.default = true;
}
res.patches = patches;
choices.push(patch);
}
choices.push(patch);
}
}
if (patches === null) {
// add a disabled option saying that patch isn't available
// note that adding `disabled: true` does nothing, so the user can
// actually select this option. I'm not 100% it's the right thing,
// but we'll keep a keen eye on user feedback.
choices.push({
value: 'skip',
key: 'p',
short: 'Patch (none available)',
name: 'Patch (no patch available, we\'ll notify you when there is one)',
});
if (patches === null) {
// add a disabled option saying that patch isn't available
// note that adding `disabled: true` does nothing, so the user can
// actually select this option. I'm not 100% it's the right thing,
// but we'll keep a keen eye on user feedback.
choices.push({
value: 'skip',
key: 'p',
short: 'Patch (none available)',
name: 'Patch (no patch available, we\'ll notify you when there is one)',
});
}
}

@@ -167,3 +451,2 @@

// kludge to make sure that we get the vuln in the user selection

@@ -173,2 +456,8 @@ res.choices = choices.map(function (choice) {

// this allows us to pass more data into the inquirer results
if (vuln.grouped && !vuln.grouped.main) {
if (!choice.meta) {
choice.meta = {};
}
choice.meta.groupId = vuln.grouped.requires;
}
choice.value = {

@@ -182,2 +471,4 @@ meta: choice.meta,

res.vuln = vuln;
return res;

@@ -202,2 +493,5 @@ });

when: function (answers) {
if (!answers[curr.name]) {
return false;
}
return answers[curr.name].choice === 'ignore';

@@ -222,3 +516,3 @@ },

function nextSteps(pkg) {
function nextSteps(pkg, skipProtect) {
var i;

@@ -239,3 +533,3 @@ var prompts = [];

i = (undefsafe(pkg, 'scripts.postinstall') || '').indexOf('snyk pro');
if (i === -1) {
if (i === -1 && !skipProtect) {
prompts.push({

@@ -242,0 +536,0 @@ name: 'misc-add-protect',

@@ -8,3 +8,3 @@ module.exports = wizard;

var debug = require('debug')('snyk');
var isAuthed = require('../auth').isAuthed;
var auth = require('../auth');
var getVersion = require('../version');

@@ -47,3 +47,3 @@ var inquirer = require('inquirer');

}).then(function (policy) {
return isAuthed().then(function (authed) {
return auth.isAuthed().then(function (authed) {
if (!authed) {

@@ -83,13 +83,8 @@ throw new Error('Unauthorized');

} else {
console.log(chalk.green('✓ Tested %s for known vulnerabilities, ' +
'no vulnerabilities found.'), res.dependencyCount);
console.log(chalk.green('✓ Tested %s dependencies for known ' +
'vulnerabilities, no vulnerabilities found.'),
res.dependencyCount);
}
if (prompts.length === 0) {
return processAnswers({}, policy, options);
}
// otherwise we're fine, but we still want to ask the user
// if they wanted to save snyk to their test process, etc.
return fs.readFile(packageFile, 'utf8')

@@ -99,3 +94,9 @@ .then(JSON.parse)

prompts = prompts.concat(allPrompts.nextSteps(pkg));
// we're fine, but we still want to ask the user if they wanted to
// save snyk to their test process, etc.
prompts = prompts.concat(allPrompts.nextSteps(pkg, res.ok));
if (prompts.length === 0) {
return processAnswers({}, policy, options);
}
return interactive(prompts, policy, options);

@@ -149,2 +150,5 @@

var task = answer.choice;
if (task === 'review') {
task = 'skip';
}

@@ -151,0 +155,0 @@ if (task === 'ignore') {

{
"API": "https://app.snyk.io/api/v1",
"API": "https://snyk.io/api/v1",
"devDeps": false
}
module.exports = createSpinner;
var isRequired = module.exports.isRequired = true;
module.exports.isRequired = true;

@@ -56,3 +56,3 @@ var debug = require('debug')('snyk:spinner');

function spinner(opt) {
if (isRequired) {
if (module.exports.isRequired) {
return false;

@@ -59,0 +59,0 @@ }

@@ -5,2 +5,3 @@ {

"main": "lib/index.js",
"version": "1.6.0-alpha1",
"directories": {

@@ -61,4 +62,3 @@ "test": "test"

"url": "https://github.com/Snyk/snyk.git"
},
"version": "1.5.1"
}
}
}

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc