diff --git a/tap-snapshots/test/lib/commands/audit.js.test.cjs b/tap-snapshots/test/lib/commands/audit.js.test.cjs index d98c16f7905a5..c3680933e6a79 100644 --- a/tap-snapshots/test/lib/commands/audit.js.test.cjs +++ b/tap-snapshots/test/lib/commands/audit.js.test.cjs @@ -5,7 +5,7 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/commands/audit.js TAP audit fix > lockfile has test-dep-a@1.0.1 1`] = ` +exports[`test/lib/commands/audit.js TAP audit fix - bulk endpoint > lockfile has test-dep-a@1.0.1 1`] = ` { "name": "test-dep", "version": "1.0.0", @@ -34,13 +34,28 @@ exports[`test/lib/commands/audit.js TAP audit fix > lockfile has test-dep-a@1.0. ` -exports[`test/lib/commands/audit.js TAP audit fix > must match snapshot 1`] = ` +exports[`test/lib/commands/audit.js TAP audit fix - bulk endpoint > must match snapshot 1`] = ` added 1 package, and audited 2 packages in xxx found 0 vulnerabilities ` +exports[`test/lib/commands/audit.js TAP fallback audit > must match snapshot 1`] = ` +# npm audit report + +test-dep-a 1.0.0 +Severity: high +Test advisory 100 - https://github.com/advisories/GHSA-100 +fix available via \`npm audit fix\` +node_modules/test-dep-a + +1 high severity vulnerability + +To address all issues, run: + npm audit fix +` + exports[`test/lib/commands/audit.js TAP json audit > must match snapshot 1`] = ` { "auditReportVersion": 2, @@ -98,14 +113,14 @@ exports[`test/lib/commands/audit.js TAP json audit > must match snapshot 1`] = ` exports[`test/lib/commands/audit.js TAP normal audit > must match snapshot 1`] = ` # npm audit report -test-dep-a * +test-dep-a 1.0.0 Severity: high Test advisory 100 - https://github.com/advisories/GHSA-100 -No fix available +fix available via \`npm audit fix\` node_modules/test-dep-a 1 high severity vulnerability -Some issues need review, and may require choosing -a different dependency. +To address all issues, run: + npm audit fix ` diff --git a/test/lib/commands/audit.js b/test/lib/commands/audit.js index 1afb8d333b7ce..da6de4774e6b8 100644 --- a/test/lib/commands/audit.js +++ b/test/lib/commands/audit.js @@ -2,9 +2,9 @@ const t = require('tap') const { load: loadMockNpm } = require('../../fixtures/mock-npm') const MockRegistry = require('../../fixtures/mock-registry.js') -const util = require('util') const zlib = require('zlib') -const gzip = util.promisify(zlib.gzip) +const gzip = zlib.gzipSync +const gunzip = zlib.gunzipSync const path = require('path') const fs = require('fs') @@ -43,7 +43,14 @@ const tree = { }, }, }), - 'test-dep-a': { + 'test-dep-a-vuln': { + 'package.json': JSON.stringify({ + name: 'test-dep-a', + version: '1.0.0', + }), + 'vulnerable.txt': 'vulnerable test-dep-a', + }, + 'test-dep-a-fixed': { 'package.json': JSON.stringify({ name: 'test-dep-a', version: '1.0.1', @@ -66,8 +73,11 @@ t.test('normal audit', async t => { packuments: [{ version: '1.0.0' }, { version: '1.0.1' }], }) await registry.package({ manifest }) - const advisory = registry.advisory({ id: 100 }) - const bulkBody = await gzip(JSON.stringify({ 'test-dep-a': ['1.0.0'] })) + const advisory = registry.advisory({ + id: 100, + vulnerable_versions: '<1.0.1', + }) + const bulkBody = gzip(JSON.stringify({ 'test-dep-a': ['1.0.0'] })) registry.nock.post('/-/npm/v1/security/advisories/bulk', bulkBody) .reply(200, { 'test-dep-a': [advisory], @@ -79,6 +89,55 @@ t.test('normal audit', async t => { t.matchSnapshot(joinedOutput()) }) +t.test('fallback audit ', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { + prefixDir: tree, + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + const manifest = registry.manifest({ + name: 'test-dep-a', + packuments: [{ version: '1.0.0' }, { version: '1.0.1' }], + }) + await registry.package({ manifest }) + const advisory = registry.advisory({ + id: 100, + module_name: 'test-dep-a', + vulnerable_versions: '<1.0.1', + findings: [{ version: '1.0.0', paths: ['test-dep-a'] }], + }) + registry.nock + .post('/-/npm/v1/security/advisories/bulk').reply(404) + .post('/-/npm/v1/security/audits/quick', body => { + const unzipped = JSON.parse(gunzip(Buffer.from(body, 'hex'))) + return t.match(unzipped, { + name: 'test-dep', + version: '1.0.0', + requires: { 'test-dep-a': '*' }, + dependencies: { 'test-dep-a': { version: '1.0.0' } }, + }) + }).reply(200, { + actions: [], + muted: [], + advisories: { + 100: advisory, + }, + metadata: { + vulnerabilities: { info: 0, low: 0, moderate: 0, high: 1, critical: 0 }, + dependencies: 1, + devDependencies: 0, + optionalDependencies: 0, + totalDependencies: 1, + }, + }) + await npm.exec('audit', []) + t.ok(process.exitCode, 'would have exited uncleanly') + process.exitCode = 0 + t.matchSnapshot(joinedOutput()) +}) + t.test('json audit', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { prefixDir: tree, @@ -97,7 +156,7 @@ t.test('json audit', async t => { }) await registry.package({ manifest }) const advisory = registry.advisory({ id: 100 }) - const bulkBody = await gzip(JSON.stringify({ 'test-dep-a': ['1.0.0'] })) + const bulkBody = gzip(JSON.stringify({ 'test-dep-a': ['1.0.0'] })) registry.nock.post('/-/npm/v1/security/advisories/bulk', bulkBody) .reply(200, { 'test-dep-a': [advisory], @@ -109,7 +168,7 @@ t.test('json audit', async t => { t.matchSnapshot(joinedOutput()) }) -t.test('audit fix', async t => { +t.test('audit fix - bulk endpoint', async t => { const { npm, joinedOutput } = await loadMockNpm(t, { prefixDir: tree, }) @@ -124,20 +183,23 @@ t.test('audit fix', async t => { await registry.package({ manifest, tarballs: { - '1.0.1': path.join(npm.prefix, 'test-dep-a'), + '1.0.1': path.join(npm.prefix, 'test-dep-a-fixed'), }, }) const advisory = registry.advisory({ id: 100, vulnerable_versions: '1.0.0' }) - // Can't validate this request body because it changes with each node - // version/npm version and nock's body validation is not async, while - // zlib.gunzip is - registry.nock.post('/-/npm/v1/security/advisories/bulk') + registry.nock.post('/-/npm/v1/security/advisories/bulk', body => { + const unzipped = JSON.parse(gunzip(Buffer.from(body, 'hex'))) + return t.same(unzipped, { 'test-dep-a': ['1.0.0'] }) + }) .reply(200, { // first audit 'test-dep-a': [advisory], }) - .post('/-/npm/v1/security/advisories/bulk') + .post('/-/npm/v1/security/advisories/bulk', body => { + const unzipped = JSON.parse(gunzip(Buffer.from(body, 'hex'))) + return t.same(unzipped, { 'test-dep-a': ['1.0.1'] }) + }) .reply(200, { // after fix - 'test-dep-a': [advisory], + 'test-dep-a': [], }) await npm.exec('audit', ['fix']) t.matchSnapshot(joinedOutput())