From e67e5db1499596fc8571d1f38b052445050a1444 Mon Sep 17 00:00:00 2001 From: Philip Harrison Date: Mon, 23 May 2022 11:06:50 +0100 Subject: [PATCH] Fix workspace tests --- lib/commands/audit.js | 13 +- .../test/lib/commands/audit.js.test.cjs | 24 +++- test/lib/commands/audit.js | 128 ++++++++++++++---- 3 files changed, 132 insertions(+), 33 deletions(-) diff --git a/lib/commands/audit.js b/lib/commands/audit.js index 58afb987b7eb6..47f5ab8bb30af 100644 --- a/lib/commands/audit.js +++ b/lib/commands/audit.js @@ -80,7 +80,9 @@ class VerifySignatures { if (this.npm.config.get('json')) { this.appendOutput(this.makeJSON({ invalid, missing })) } else { - const timing = `audited ${this.audited} packages in ${Math.floor(Number(elapsed) / 1e9)}s` + const auditedPlural = this.audited > 1 ? 's' : '' + const timing = `audited ${this.audited} package${auditedPlural} in ` + + `${Math.floor(Number(elapsed) / 1e9)}s` const verifiedPrefix = verified ? 'verified registry signatures, ' : '' this.appendOutput(`${verifiedPrefix}${timing}\n`) @@ -119,9 +121,9 @@ class VerifySignatures { `${missing.length ? '\n' : ''}${invalid.length} ${msg}:\n` ) this.appendOutput(this.humanOutput(invalid)) - const plural = invalid.length === 1 ? '' : 's' + const invPlural = invalid.length === 1 ? '' : 's' this.appendOutput( - `\nSomeone might have tampered with the package${plural} ` + + `\nSomeone might have tampered with the package${invPlural} ` + `since it was published on the registry (monster-in-the-middle attack)!\n` ) } @@ -199,6 +201,11 @@ class VerifySignatures { : edge.dev ? 'devDependencies' : 'dependencies' + // Skip local workspaces + if (node.isWorkspace) { + return + } + // Skip potentially optional packages that are not on disk, as these could // be omitted during install if (edge.error === 'MISSING' && type !== 'dependencies') { diff --git a/tap-snapshots/test/lib/commands/audit.js.test.cjs b/tap-snapshots/test/lib/commands/audit.js.test.cjs index 80dfeb2450c45..5e982972c0d0d 100644 --- a/tap-snapshots/test/lib/commands/audit.js.test.cjs +++ b/tap-snapshots/test/lib/commands/audit.js.test.cjs @@ -42,7 +42,7 @@ found 0 vulnerabilities ` exports[`test/lib/commands/audit.js TAP audit signatures ignores optional dependencies > must match snapshot 1`] = ` -verified registry signatures, audited 1 packages in xxx +verified registry signatures, audited 1 package in 0s ` @@ -85,12 +85,12 @@ exports[`test/lib/commands/audit.js TAP audit signatures json output with valid ` exports[`test/lib/commands/audit.js TAP audit signatures omit dev dependencies with missing signature > must match snapshot 1`] = ` -verified registry signatures, audited 1 packages in xxx +verified registry signatures, audited 1 package in 0s ` exports[`test/lib/commands/audit.js TAP audit signatures output details about missing signatures > must match snapshot 1`] = ` -audited 1 packages in xxx +audited 1 package in 0s 1 package has a missing registry signature but the registry is providing signing keys: @@ -112,7 +112,7 @@ Someone might have tampered with the package since it was published on the regis ` exports[`test/lib/commands/audit.js TAP audit signatures with colour option and invalid signatures > must match snapshot 1`] = ` -audited 1 packages in xxx +audited 1 package in 0s 1 package has an invalid registry signature: @@ -123,7 +123,7 @@ Someone might have tampered with the package since it was published on the regis ` exports[`test/lib/commands/audit.js TAP audit signatures with invalid signatures > must match snapshot 1`] = ` -audited 1 packages in xxx +audited 1 package in 0s 1 package has an invalid registry signature: @@ -134,7 +134,7 @@ Someone might have tampered with the package since it was published on the regis ` exports[`test/lib/commands/audit.js TAP audit signatures with keys but missing signature > must match snapshot 1`] = ` -audited 1 packages in xxx +audited 1 package in 0s 1 package has a missing registry signature but the registry is providing signing keys run \`npm audit signatures --missing\` for details @@ -150,7 +150,17 @@ audited 2 packages in xxx ` exports[`test/lib/commands/audit.js TAP audit signatures with valid signatures > must match snapshot 1`] = ` -verified registry signatures, audited 1 packages in xxx +verified registry signatures, audited 1 package in 0s + +` + +exports[`test/lib/commands/audit.js TAP audit signatures workspaces verifies registry deps and ignores local workspace deps > must match snapshot 1`] = ` +verified registry signatures, audited 3 packages in xxx + +` + +exports[`test/lib/commands/audit.js TAP audit signatures workspaces verifies registry deps when filtering by workspace name > must match snapshot 1`] = ` +verified registry signatures, audited 2 packages in xxx ` diff --git a/test/lib/commands/audit.js b/test/lib/commands/audit.js index 4d6751546a451..6a7618abb4c35 100644 --- a/test/lib/commands/audit.js +++ b/test/lib/commands/audit.js @@ -379,16 +379,16 @@ t.test('audit signatures', async t => { version: '1.0.0', }), }, - foo: { + async: { 'package.json': JSON.stringify({ - name: 'foo', - version: '1.0.0', + name: 'async', + version: '2.5.0', }), }, - zeta: { + 'light-cycle': { 'package.json': JSON.stringify({ - name: 'zeta', - version: '1.0.0', + name: 'light-cycle', + version: '1.4.2', }), }, }, @@ -399,7 +399,7 @@ t.test('audit signatures', async t => { version: '1.0.0', dependencies: { b: '^1.0.0', - foo: '^1.0.0', + async: '^2.0.0', }, }), }, @@ -408,7 +408,7 @@ t.test('audit signatures', async t => { name: 'b', version: '1.0.0', dependencies: { - zeta: '^1.0.0', + 'light-cycle': '^1.0.0', }, }), }, @@ -416,9 +416,6 @@ t.test('audit signatures', async t => { 'package.json': JSON.stringify({ name: 'c', version: '1.0.0', - dependencies: { - theta: '^1.0.0', - }, }), }, }, @@ -642,7 +639,7 @@ t.test('audit signatures', async t => { t.equal(process.exitCode, 0, 'should exit successfully') process.exitCode = 0 - t.match(joinedOutput(), /verified registry signatures, audited 1 packages/) + t.match(joinedOutput(), /verified registry signatures, audited 1 package/) t.matchSnapshot(joinedOutput()) }) @@ -834,7 +831,7 @@ t.test('audit signatures', async t => { t.equal(process.exitCode, 0, 'should exit successfully') process.exitCode = 0 - t.match(joinedOutput(), /verified registry signatures, audited 1 packages/) + t.match(joinedOutput(), /verified registry signatures, audited 1 package/) t.matchSnapshot(joinedOutput()) }) @@ -873,7 +870,7 @@ t.test('audit signatures', async t => { t.equal(process.exitCode, 0, 'should exit successfully') process.exitCode = 0 - t.match(joinedOutput(), /verified registry signatures, audited 1 packages/) + t.match(joinedOutput(), /verified registry signatures, audited 1 package/) t.matchSnapshot(joinedOutput()) }) @@ -961,33 +958,118 @@ t.test('audit signatures', async t => { }) t.test('workspaces', async t => { - t.test('verifies registry deps and ignores local workspace deps', { todo: true }, async t => { + t.test('verifies registry deps and ignores local workspace deps', async t => { npm.prefix = workspaceInstall() await manifestWithValidSigs() + const asyncManifest = registry.manifest({ + name: 'async', + packuments: [{ + version: '2.5.0', + dist: { + tarball: 'https://registry.npmjs.org/async/-/async-2.5.0.tgz', + integrity: 'sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFT' + + 'KE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==', + signatures: [ + { + keyid: 'SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA', + sig: 'MEUCIQCM8cX2U3IVZKKhzQx1w5AlNSDUI+fVf4857K1qT0NTNgIgdT4qwEl' + + '/kg2vU1uIWUI0bGikRvVHCHlRs1rgjPMpRFA=', + }, + ], + }, + }], + }) + const lightCycleManifest = registry.manifest({ + name: 'light-cycle', + packuments: [{ + version: '1.4.2', + dist: { + tarball: 'https://registry.npmjs.org/light-cycle/-/light-cycle-1.4.2.tgz', + integrity: 'sha512-badZ3KMUaGwQfVcHjXTXSecYSXxT6f99bT+kVzBqmO10U1UNlE' + + 'thJ1XAok97E4gfDRTA2JJ3r0IeMPtKf0EJMw==', + signatures: [ + { + keyid: 'SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA', + sig: 'MEUCIQDXjoxQz4MzPqaIuy2RJmBlcFp0UD3h9EhKZxxEz9IYZAIgLO0znG5' + + 'aGciTAg4u8fE0/UXBU4gU7JcvTZGxW2BmKGw=', + }, + ], + }, + }], + }) + await registry.package({ manifest: asyncManifest }) + await registry.package({ manifest: lightCycleManifest }) validKeys() await audit.exec(['signatures']) t.equal(process.exitCode, 0, 'should exit successfully') process.exitCode = 0 - t.match(joinedOutput(), /verified registry signatures, audited 1 packages/) + t.match(joinedOutput(), /verified registry signatures, audited 3 packages/) t.matchSnapshot(joinedOutput()) }) - // TODO: This should verify kms-demo, but doesn't because arborist filters - // workspace deps even if they're also root deps - t.test('verifies registry dep if workspaces is disabled', { todo: true }, async t => { + t.test('verifies registry deps when filtering by workspace name', async t => { npm.prefix = workspaceInstall() - npm.flatOptions.workspacesEnabled = false - await manifestWithValidSigs() + npm.localPrefix = npm.prefix + const asyncManifest = registry.manifest({ + name: 'async', + packuments: [{ + version: '2.5.0', + dist: { + tarball: 'https://registry.npmjs.org/async/-/async-2.5.0.tgz', + integrity: 'sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFT' + + 'KE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==', + signatures: [ + { + keyid: 'SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA', + sig: 'MEUCIQCM8cX2U3IVZKKhzQx1w5AlNSDUI+fVf4857K1qT0NTNgIgdT4qwEl' + + '/kg2vU1uIWUI0bGikRvVHCHlRs1rgjPMpRFA=', + }, + ], + }, + }], + }) + const lightCycleManifest = registry.manifest({ + name: 'light-cycle', + packuments: [{ + version: '1.4.2', + dist: { + tarball: 'https://registry.npmjs.org/light-cycle/-/light-cycle-1.4.2.tgz', + integrity: 'sha512-badZ3KMUaGwQfVcHjXTXSecYSXxT6f99bT+kVzBqmO10U1UNlE' + + 'thJ1XAok97E4gfDRTA2JJ3r0IeMPtKf0EJMw==', + signatures: [ + { + keyid: 'SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA', + sig: 'MEUCIQDXjoxQz4MzPqaIuy2RJmBlcFp0UD3h9EhKZxxEz9IYZAIgLO0znG5' + + 'aGciTAg4u8fE0/UXBU4gU7JcvTZGxW2BmKGw=', + }, + ], + }, + }], + }) + await registry.package({ manifest: asyncManifest }) + await registry.package({ manifest: lightCycleManifest }) validKeys() - await audit.exec(['signatures']) + await audit.execWorkspaces(['signatures'], ['./packages/a']) t.equal(process.exitCode, 0, 'should exit successfully') process.exitCode = 0 - t.match(joinedOutput(), /verified registry signatures, audited 1 packages/) + t.match(joinedOutput(), /verified registry signatures, audited 2 packages/) t.matchSnapshot(joinedOutput()) }) + + // TODO: This should verify kms-demo, but doesn't because arborist filters + // workspace deps even if they're also root deps + t.test('verifies registry dep if workspaces is disabled', async t => { + npm.prefix = workspaceInstall() + npm.flatOptions.workspacesEnabled = false + + await t.rejects( + audit.exec(['signatures']), + /No dependencies found in current install/ + ) + }) }) })