diff options
Diffstat (limited to 'deps/npm/test/tap/audit-fix.js')
-rw-r--r-- | deps/npm/test/tap/audit-fix.js | 669 |
1 files changed, 669 insertions, 0 deletions
diff --git a/deps/npm/test/tap/audit-fix.js b/deps/npm/test/tap/audit-fix.js new file mode 100644 index 0000000000..579d43a798 --- /dev/null +++ b/deps/npm/test/tap/audit-fix.js @@ -0,0 +1,669 @@ +'use strict' + +const BB = require('bluebird') + +const common = BB.promisifyAll(require('../common-tap.js')) +const fs = require('fs') +const mr = BB.promisify(require('npm-registry-mock')) +const path = require('path') +const rimraf = BB.promisify(require('rimraf')) +const Tacks = require('tacks') +const tap = require('tap') +const test = tap.test + +const Dir = Tacks.Dir +const File = Tacks.File +const testDir = path.join(__dirname, path.basename(__filename, '.js')) + +const EXEC_OPTS = { cwd: testDir } + +tap.tearDown(function () { + process.chdir(__dirname) + try { + rimraf.sync(testDir) + } catch (e) { + if (process.platform !== 'win32') { + throw e + } + } +}) + +function tmock (t) { + return mr({port: common.port}).then(s => { + t.tearDown(function () { + s.done() + s.close() + rimraf.sync(testDir) + }) + return s + }) +} + +test('fixes shallow vulnerabilities', t => { + const fixture = new Tacks(new Dir({ + 'package.json': new File({ + name: 'foo', + version: '1.0.0', + dependencies: { + baddep: '1.0.0' + } + }) + })) + fixture.create(testDir) + return tmock(t).then(srv => { + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits/quick', 'ok').reply(200, 'yeah') + srv.get('/baddep').twice().reply(200, { + name: 'baddep', + 'dist-tags': { + 'latest': '1.2.3' + }, + versions: { + '1.0.0': { + name: 'baddep', + version: '1.0.0', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-1.0.0.tgz' + } + }, + '1.2.3': { + name: 'baddep', + version: '1.2.3', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-1.2.3.tgz' + } + } + } + }) + return common.npm([ + 'install', + '--audit', + '--json', + '--package-lock-only', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'baddep', + version: '1.0.0' + }] + }, 'installed bad version') + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits', 'ok').reply(200, { + actions: [{ + action: 'update', + module: 'baddep', + target: '1.2.3', + resolves: [{path: 'baddep'}] + }], + metadata: { + vulnerabilities: { + critical: 1 + } + } + }) + return common.npm([ + 'audit', 'fix', + '--package-lock-only', + '--json', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'baddep', + version: '1.2.3' + }] + }, 'reported dependency update') + t.similar(JSON.parse(fs.readFileSync(path.join(testDir, 'package-lock.json'), 'utf8')), { + dependencies: { + baddep: { + version: '1.2.3', + resolved: common.registry + '/idk/-/idk-1.2.3.tgz', + integrity: 'sha1-3q2+7w==' + } + } + }, 'pkglock updated correctly') + }) + }) + }) +}) + +test('fixes nested dep vulnerabilities', t => { + const fixture = new Tacks(new Dir({ + 'package.json': new File({ + name: 'foo', + version: '1.0.0', + dependencies: { + gooddep: '^1.0.0' + } + }) + })) + fixture.create(testDir) + return tmock(t).then(srv => { + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits/quick', 'ok').reply(200, 'yeah') + srv.get('/baddep').reply(200, { + name: 'baddep', + 'dist-tags': { + 'latest': '1.0.0' + }, + versions: { + '1.0.0': { + name: 'baddep', + version: '1.0.0', + _hasShrinkwrap: false, + dist: { + shasum: 'c0ffee', + integrity: 'sha1-c0ffee', + tarball: common.registry + '/baddep/-/baddep-1.0.0.tgz' + } + }, + '1.2.3': { + name: 'baddep', + version: '1.2.3', + _hasShrinkwrap: false, + dist: { + shasum: 'bada55', + integrity: 'sha1-bada55', + tarball: common.registry + '/baddep/-/baddep-1.2.3.tgz' + } + } + } + }) + + srv.get('/gooddep').reply(200, { + name: 'gooddep', + 'dist-tags': { + 'latest': '1.0.0' + }, + versions: { + '1.0.0': { + name: 'gooddep', + version: '1.0.0', + dependencies: { + baddep: '^1.0.0' + }, + _hasShrinkwrap: false, + dist: { + shasum: '1234', + tarball: common.registry + '/gooddep/-/gooddep-1.0.0.tgz' + } + }, + '1.2.3': { + name: 'gooddep', + version: '1.2.3', + _hasShrinkwrap: false, + dependencies: { + baddep: '^1.0.0' + }, + dist: { + shasum: '123456', + tarball: common.registry + '/gooddep/-/gooddep-1.2.3.tgz' + } + } + } + }) + + return common.npm([ + 'install', + '--audit', + '--json', + '--global-style', + '--package-lock-only', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'baddep', + version: '1.0.0' + }, { + action: 'add', + name: 'gooddep', + version: '1.0.0' + }] + }, 'installed bad version') + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits', 'ok').reply(200, { + actions: [{ + action: 'update', + module: 'baddep', + target: '1.2.3', + resolves: [{path: 'gooddep>baddep'}] + }], + metadata: { + vulnerabilities: { + critical: 1 + } + } + }) + return common.npm([ + 'audit', 'fix', + '--package-lock-only', + '--offline', + '--json', + '--global-style', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'baddep', + version: '1.2.3' + }, { + action: 'add', + name: 'gooddep', + version: '1.0.0' + }] + }, 'reported dependency update') + t.similar(JSON.parse(fs.readFileSync(path.join(testDir, 'package-lock.json'), 'utf8')), { + dependencies: { + gooddep: { + version: '1.0.0', + resolved: common.registry + '/gooddep/-/gooddep-1.0.0.tgz', + integrity: 'sha1-EjQ=', + requires: { + baddep: '^1.0.0' + }, + dependencies: { + baddep: { + version: '1.2.3', + resolved: common.registry + '/baddep/-/baddep-1.2.3.tgz', + integrity: 'sha1-bada55' + } + } + } + } + }, 'pkglock updated correctly') + }) + }) + }) +}) + +test('no semver-major without --force', t => { + const fixture = new Tacks(new Dir({ + 'package.json': new File({ + name: 'foo', + version: '1.0.0', + dependencies: { + baddep: '1.0.0' + } + }) + })) + fixture.create(testDir) + return tmock(t).then(srv => { + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits/quick', 'ok').reply(200, 'yeah') + srv.get('/baddep').twice().reply(200, { + name: 'baddep', + 'dist-tags': { + 'latest': '2.0.0' + }, + versions: { + '1.0.0': { + name: 'baddep', + version: '1.0.0', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-1.0.0.tgz' + } + }, + '2.0.0': { + name: 'baddep', + version: '2.0.0', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-2.0.0.tgz' + } + } + } + }) + return common.npm([ + 'install', + '--audit', + '--json', + '--package-lock-only', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'baddep', + version: '1.0.0' + }] + }, 'installed bad version') + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits', 'ok').reply(200, { + actions: [{ + action: 'install', + module: 'baddep', + target: '2.0.0', + isMajor: true, + resolves: [{path: 'baddep'}] + }], + metadata: { + vulnerabilities: { + critical: 1 + } + } + }) + return common.npm([ + 'audit', 'fix', + '--package-lock-only', + '--registry', common.registry, + '--loglevel=warn', + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.match(stdout, /breaking changes/, 'informs about semver-major') + t.match(stdout, /npm audit fix --force/, 'recommends --force') + t.similar(JSON.parse(fs.readFileSync(path.join(testDir, 'package-lock.json'), 'utf8')), { + dependencies: { + baddep: { + version: '1.0.0' + } + } + }, 'pkglock not updated') + }) + }) + }) +}) + +test('semver-major when --force', t => { + const fixture = new Tacks(new Dir({ + 'package.json': new File({ + name: 'foo', + version: '1.0.0', + dependencies: { + baddep: '1.0.0' + } + }) + })) + fixture.create(testDir) + return tmock(t).then(srv => { + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits/quick', 'ok').reply(200, 'yeah') + srv.get('/baddep').twice().reply(200, { + name: 'baddep', + 'dist-tags': { + 'latest': '2.0.0' + }, + versions: { + '1.0.0': { + name: 'baddep', + version: '1.0.0', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-1.0.0.tgz' + } + }, + '2.0.0': { + name: 'baddep', + version: '2.0.0', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-2.0.0.tgz' + } + } + } + }) + return common.npm([ + 'install', + '--audit', + '--json', + '--package-lock-only', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'baddep', + version: '1.0.0' + }] + }, 'installed bad version') + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits', 'ok').reply(200, { + actions: [{ + action: 'install', + module: 'baddep', + target: '2.0.0', + isMajor: true, + resolves: [{path: 'baddep'}] + }], + metadata: { + vulnerabilities: { + critical: 1 + } + } + }) + return common.npm([ + 'audit', 'fix', + '--package-lock-only', + '--registry', common.registry, + '--force', + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.match(stdout, /breaking changes/, 'informs about semver-major') + t.similar(JSON.parse(fs.readFileSync(path.join(testDir, 'package-lock.json'), 'utf8')), { + dependencies: { + baddep: { + version: '2.0.0' + } + } + }, 'pkglock not updated') + }) + }) + }) +}) + +test('no installs for review-requires', t => { + const fixture = new Tacks(new Dir({ + 'package.json': new File({ + name: 'foo', + version: '1.0.0', + dependencies: { + baddep: '1.0.0' + } + }) + })) + fixture.create(testDir) + return tmock(t).then(srv => { + srv.filteringRequestBody(req => 'k') + srv.post('/-/npm/v1/security/audits/quick', 'k').reply(200, 'yeah') + srv.get('/baddep').twice().reply(200, { + name: 'baddep', + 'dist-tags': { + 'latest': '1.2.3' + }, + versions: { + '1.0.0': { + name: 'baddep', + version: '1.0.0', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-1.0.0.tgz' + } + }, + '1.2.3': { + name: 'baddep', + version: '1.2.3', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-1.2.3.tgz' + } + } + } + }) + return common.npm([ + 'install', + '--audit', + '--json', + '--package-lock-only', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'baddep', + version: '1.0.0' + }] + }, 'installed bad version') + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits', 'ok').reply(200, { + actions: [{ + action: 'review', + module: 'baddep', + target: '1.2.3', + resolves: [{path: 'baddep'}] + }], + metadata: { + vulnerabilities: { + critical: 1 + } + } + }) + return common.npm([ + 'audit', 'fix', + '--package-lock-only', + '--json', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'baddep', + version: '1.0.0' + }] + }, 'no update for dependency') + }) + }) + }) +}) + +test('nothing to fix', t => { + const fixture = new Tacks(new Dir({ + 'package.json': new File({ + name: 'foo', + version: '1.0.0', + dependencies: { + gooddep: '1.0.0' + } + }) + })) + fixture.create(testDir) + return tmock(t).then(srv => { + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits/quick', 'ok').reply(200, 'yeah') + srv.get('/gooddep').twice().reply(200, { + name: 'gooddep', + 'dist-tags': { + 'latest': '1.2.3' + }, + versions: { + '1.0.0': { + name: 'gooddep', + version: '1.0.0', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-1.0.0.tgz' + } + }, + '1.2.3': { + name: 'gooddep', + version: '1.2.3', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-1.2.3.tgz' + } + } + } + }) + return common.npm([ + 'install', + '--audit', + '--json', + '--package-lock-only', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'gooddep', + version: '1.0.0' + }] + }, 'installed good version') + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits', 'ok').reply(200, { + actions: [], + metadata: { + vulnerabilities: { } + } + }) + return common.npm([ + 'audit', 'fix', + '--package-lock-only', + '--json', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'gooddep', + version: '1.0.0' + }] + }, 'nothing to update') + }) + }) + }) +}) + +test('cleanup', t => { + return rimraf(testDir) +}) |