Skip to content

Commit 037ea82

Browse files
committed
Use pacote.manifest and cleanup output
1 parent c2af69d commit 037ea82

1 file changed

Lines changed: 56 additions & 78 deletions

File tree

lib/commands/audit.js

Lines changed: 56 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ const fetch = require('npm-registry-fetch')
66
const localeCompare = require('@isaacs/string-locale-compare')('en')
77
const npa = require('npm-package-arg')
88
const pacote = require('pacote')
9-
const pickManifest = require('npm-pick-manifest')
10-
const table = require('text-table')
9+
// const pickManifest = require('npm-pick-manifest')
1110

1211
const ArboristWorkspaceCmd = require('../arborist-cmd.js')
13-
const ansiTrim = require('../utils/ansi-trim.js')
1412
const auditError = require('../utils/audit-error.js')
13+
const {
14+
registry: { default: defaultRegistry },
15+
} = require('../utils/config/definitions.js')
16+
// const log = require('../utils/log-shim.js')
1517
const reifyFinish = require('../utils/reify-finish.js')
1618

1719
const validateSignature = async ({ message, signature, publicKey }) => {
@@ -37,27 +39,26 @@ class VerifySignatures {
3739
}
3840

3941
async run () {
42+
const start = process.hrtime.bigint()
43+
4044
// Find all deps in tree
4145
const nodes = this.tree.inventory.values()
4246
this.getEdges(nodes, 'edgesOut')
43-
4447
const edges = Array.from(this.edges)
45-
const start = process.hrtime.bigint()
46-
const registries = this.findAllRegistryUrls(edges, this.npm.flatOptions)
4748

48-
// Prefetch and cache public keys from the used registries
49+
// QUESTION: Do we need to get the registry host from the resolved url to handle proxies?
50+
// Prefetch and cache public keys from used registries
51+
const registries = this.findAllRegistryUrls(edges, this.npm.flatOptions)
4952
for (const registry of registries) {
5053
const keys = await this.getKeys({ registry })
5154
if (keys) {
5255
this.keys.set(registry, keys)
5356
}
5457
}
55-
await Promise.all(edges.map((edge) => this.getVerifiedInfo(edge)))
5658

57-
const end = process.hrtime.bigint()
58-
const elapsed = end - start
59+
await Promise.all(edges.map((edge) => this.getVerifiedInfo(edge)))
5960

60-
// sort alphabetically
61+
// Sort alphabetically
6162
const invalid = Array.from(this.invalid).sort((a, b) => localeCompare(a.name, b.name))
6263
const missing = Array.from(this.missing).sort((a, b) => localeCompare(a.name, b.name))
6364

@@ -67,13 +68,20 @@ class VerifySignatures {
6768
this.exitCode = 1
6869
}
6970

71+
const end = process.hrtime.bigint()
72+
const elapsed = end - start
73+
7074
if (this.npm.config.get('json')) {
7175
this.appendOutput(this.makeJSON({ invalid, missing }))
7276
} else {
7377
const timing = `audited ${edges.length} packages in ${Math.floor(Number(elapsed) / 1e9)}s`
7478
const verifiedPrefix = verified ? 'verified signatures, ' : ''
7579
this.appendOutput(`${verifiedPrefix}${timing}\n`)
7680

81+
if (this.verified && !verified) {
82+
this.appendOutput(`${this.verified} ${chalk.bold('verified')} packages\n`)
83+
}
84+
7785
if (missing.length) {
7886
const msg = missing.length === 1 ?
7987
`package has a ${chalk.bold(chalk.magenta('missing'))} registry signature` :
@@ -183,6 +191,7 @@ class VerifySignatures {
183191
}
184192
}
185193

194+
// TODO: Remove this once we can get time from pacote.manifest
186195
async getPackument (spec) {
187196
const packument = await pacote.packument(spec, {
188197
...this.npm.flatOptions,
@@ -218,6 +227,7 @@ class VerifySignatures {
218227
const node = edge.to || edge
219228
const { path, location } = node
220229
const { version } = node.package || {}
230+
// QUESTION: Do we need to handle `latest`?
221231
if (!version) {
222232
return
223233
}
@@ -232,51 +242,56 @@ class VerifySignatures {
232242
}
233243
}
234244

245+
// QUESTION: Confirm, is this the right thing to do here?
246+
//
235247
// deps different from prod not currently
236248
// on disk are not included in the output
237249
if (edge.error === 'MISSING' && type !== 'dependencies') {
238250
return
239251
}
240252

253+
// QUESTION: Confirm, is this the right thing to do here?
254+
//
255+
// if it's not a range, version, or tag, skip it
241256
try {
242-
const packument = await this.getPackument(spec)
243-
// if it's not a range, version, or tag, skip it
244-
try {
245-
if (!npa(`${edge.name}@${edge.spec}`).registry) {
246-
return null
247-
}
248-
} catch (err) {
257+
if (!npa(`${edge.name}@${edge.spec}`).registry) {
249258
return null
250259
}
260+
} catch (err) {
261+
return null
262+
}
251263

264+
try {
252265
const name = alias ? edge.spec.replace('npm', edge.name) : edge.name
253-
const { homepage } = packument
254-
266+
// QUESTION: Is name@version the right way to get the manifest?
267+
const manifest = await pacote.manifest(`${name}@${version}`, this.npm.flatOptions)
255268
const registry = fetch.pickRegistry(spec, this.npm.flatOptions)
256269

257-
const versionPackument = pickManifest(packument, version, this.npm.flatOptions)
258-
const versionCreated = packument.time && packument.time[version]
259-
const dist = versionPackument.dist || {}
260-
const { integrity } = dist
270+
const { _integrity: integrity, _signatures } = manifest
261271
const message = `${name}@${version}:${integrity}`
262-
const signatures = dist.signatures || []
272+
const signatures = _signatures || []
273+
274+
// TODO: Get version created time from manifest
275+
//
276+
// const packument = await this.getPackument(spec)
277+
// const versionCreated = packument.time && packument.time[version]
263278
const keys = this.keys.get(registry) || []
264279
const validKeys = keys.filter((publicKey) => {
265280
if (!publicKey.expires) {
266281
return true
267282
}
268-
return Date.parse(versionCreated) < Date.parse(publicKey.expires)
283+
// return Date.parse(versionCreated) < Date.parse(publicKey.expires)
284+
return Date.parse(publicKey.expires) > Date.now()
269285
})
270286

271287
// Currently we only care about missing signatures on registries that provide a public key
272-
// Note: we could make this configurable in the future with a strict/paranoid mode
288+
// We could make this configurable in the future with a strict/paranoid mode
273289
if (!signatures.length && validKeys.length) {
274290
this.missing.add({
275291
name,
276292
path,
277293
version,
278294
location,
279-
homepage,
280295
registry,
281296
})
282297

@@ -313,7 +328,6 @@ class VerifySignatures {
313328
type,
314329
version,
315330
location,
316-
homepage,
317331
registry,
318332
integrity,
319333
signature: signature.sig,
@@ -324,6 +338,8 @@ class VerifySignatures {
324338
}
325339
}))
326340
} catch (err) {
341+
// QUESTION: Is this the right way to handle these errors?
342+
//
327343
// silently catch and ignore ETARGET, E403 &
328344
// E404 errors, deps are just skipped
329345
if (!(
@@ -337,52 +353,18 @@ class VerifySignatures {
337353
}
338354

339355
humanOutput (list) {
340-
const invalidList = list.map(x => this.makePretty(x))
341-
const outHead = ['Package',
342-
'Version',
343-
'Location',
344-
'Registry',
345-
]
346-
347-
if (this.npm.config.get('long')) {
348-
outHead[4] = 'Homepage'
349-
}
350-
351-
const outTable = [outHead].concat(invalidList)
352-
353-
if (this.npm.color) {
354-
outTable[0] = outTable[0].map(heading => chalk.underline(heading))
355-
}
356-
357-
const tableOpts = {
358-
align: ['l', 'r', 'r', 'r', 'l'],
359-
stringLength: s => ansiTrim(s).length,
360-
}
361-
362-
return table(outTable, tableOpts)
363-
}
364-
365-
// formatting functions
366-
makePretty (dep) {
367-
const {
368-
version = 'MISSING',
369-
homepage = '',
370-
name,
371-
location,
372-
registry,
373-
} = dep
374-
375-
const columns = [name, version, location, registry]
376-
377-
if (this.npm.config.get('long')) {
378-
columns[4] = homepage
379-
}
380-
381-
if (this.npm.color) {
382-
columns[0] = chalk.red(columns[0])
383-
}
356+
const uniquePackages = Array.from(list.reduce((set, v) => {
357+
let nameVersion = `${v.name}@${v.version}`
358+
if (this.npm.color) {
359+
nameVersion = chalk.red(nameVersion)
360+
}
361+
const registry = v.registry
362+
const suffix = registry !== defaultRegistry ? ` (${registry})` : ''
363+
set.add(`${nameVersion}${suffix}`)
364+
return set
365+
}, new Set()))
384366

385-
return columns
367+
return uniquePackages.join('\n')
386368
}
387369

388370
makeJSON ({ invalid, missing }) {
@@ -396,7 +378,6 @@ class VerifySignatures {
396378
integrity,
397379
signature,
398380
keyid,
399-
homepage,
400381
} = dep
401382
out.invalid = out.invalid || {}
402383
out.invalid[name] = {
@@ -406,7 +387,6 @@ class VerifySignatures {
406387
signature,
407388
integrity,
408389
keyid,
409-
homepage,
410390
}
411391
})
412392
missing.forEach(dep => {
@@ -415,14 +395,12 @@ class VerifySignatures {
415395
version,
416396
path,
417397
registry,
418-
homepage,
419398
} = dep
420399
out.missing = out.invalid || {}
421400
out.missing[name] = {
422401
version,
423402
location: path,
424403
registry,
425-
homepage,
426404
}
427405
})
428406
return JSON.stringify(out, null, 2)

0 commit comments

Comments
 (0)