Skip to content

Commit 42e0587

Browse files
wraithgarruyadorno
authored andcommitted
fix(pack): refuse to pack invalid packument
If name and version are missing, the filename won't make sense. This also slightly reorders operations so that it will bail early on multiple packages, not potentially packing some before hitting an invalid package and bailing. PR-URL: #3115 Credit: @wraithgar Close: #3115 Reviewed-by: @nlf
1 parent 4c1f16d commit 42e0587

File tree

2 files changed

+68
-30
lines changed

2 files changed

+68
-30
lines changed

lib/pack.js

+17-5
Original file line numberDiff line numberDiff line change
@@ -45,22 +45,34 @@ class Pack extends BaseCommand {
4545
args = ['.']
4646

4747
const unicode = this.npm.config.get('unicode')
48+
const dryRun = this.npm.config.get('dry-run')
4849

49-
// clone the opts because pacote mutates it with resolved/integrity
50-
const tarballs = await Promise.all(args.map(async (arg) => {
50+
// Get the manifests and filenames first so we can bail early on manifest
51+
// errors before making any tarballs
52+
const manifests = []
53+
for (const arg of args) {
5154
const spec = npa(arg)
52-
const dryRun = this.npm.config.get('dry-run')
5355
const manifest = await pacote.manifest(spec, this.npm.flatOptions)
56+
if (!manifest._id)
57+
throw new Error('Invalid package, must have name and version')
58+
5459
const filename = `${manifest.name}-${manifest.version}.tgz`
5560
.replace(/^@/, '').replace(/\//, '-')
61+
manifests.push({ arg, filename, manifest })
62+
}
63+
64+
// Load tarball names up for printing afterward to isolate from the
65+
// noise generated during packing
66+
const tarballs = []
67+
for (const { arg, filename, manifest } of manifests) {
5668
const tarballData = await libpack(arg, this.npm.flatOptions)
5769
const pkgContents = await getContents(manifest, tarballData)
5870

5971
if (!dryRun)
6072
await writeFile(filename, tarballData)
6173

62-
return pkgContents
63-
}))
74+
tarballs.push(pkgContents)
75+
}
6476

6577
for (const tar of tarballs) {
6678
logTar(tar, { log, unicode })

test/lib/pack.js

+51-25
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ const mockPacote = {
1515
manifest: (spec) => {
1616
if (spec.type === 'directory')
1717
return pacote.manifest(spec)
18-
return {
18+
const m = {
1919
name: spec.name || 'test-package',
2020
version: spec.version || '1.0.0-test',
2121
}
22+
m._id = `${m.name}@${m.version}`
23+
return m
2224
},
2325
}
2426

@@ -43,9 +45,8 @@ t.test('should pack current directory with no arguments', (t) => {
4345
})
4446
const pack = new Pack(npm)
4547

46-
pack.exec([], er => {
47-
if (er)
48-
throw er
48+
pack.exec([], err => {
49+
t.error(err, { bail: true })
4950

5051
const filename = `npm-${require('../../package.json').version}.tgz`
5152
t.strictSame(OUTPUT, [[filename]])
@@ -79,9 +80,8 @@ t.test('should pack given directory', (t) => {
7980
})
8081
const pack = new Pack(npm)
8182

82-
pack.exec([testDir], er => {
83-
if (er)
84-
throw er
83+
pack.exec([testDir], err => {
84+
t.error(err, { bail: true })
8585

8686
const filename = 'my-cool-pkg-1.0.0.tgz'
8787
t.strictSame(OUTPUT, [[filename]])
@@ -115,9 +115,8 @@ t.test('should pack given directory for scoped package', (t) => {
115115
})
116116
const pack = new Pack(npm)
117117

118-
return pack.exec([testDir], er => {
119-
if (er)
120-
throw er
118+
return pack.exec([testDir], err => {
119+
t.error(err, { bail: true })
121120

122121
const filename = 'cool-my-pkg-1.0.0.tgz'
123122
t.strictSame(OUTPUT, [[filename]])
@@ -150,16 +149,47 @@ t.test('should log pack contents', (t) => {
150149
})
151150
const pack = new Pack(npm)
152151

153-
pack.exec([], er => {
154-
if (er)
155-
throw er
152+
pack.exec([], err => {
153+
t.error(err, { bail: true })
156154

157155
const filename = `npm-${require('../../package.json').version}.tgz`
158156
t.strictSame(OUTPUT, [[filename]])
159157
t.end()
160158
})
161159
})
162160

161+
t.test('invalid packument', (t) => {
162+
const mockPacote = {
163+
manifest: () => {
164+
return {}
165+
},
166+
}
167+
const Pack = t.mock('../../lib/pack.js', {
168+
libnpmpack,
169+
pacote: mockPacote,
170+
npmlog: {
171+
notice: () => {},
172+
showProgress: () => {},
173+
clearProgress: () => {},
174+
},
175+
})
176+
const npm = mockNpm({
177+
config: {
178+
unicode: true,
179+
json: true,
180+
'dry-run': true,
181+
},
182+
output,
183+
})
184+
const pack = new Pack(npm)
185+
pack.exec([], err => {
186+
t.match(err, { message: 'Invalid package, must have name and version' })
187+
188+
t.strictSame(OUTPUT, [])
189+
t.end()
190+
})
191+
})
192+
163193
t.test('workspaces', (t) => {
164194
const testDir = t.testdir({
165195
'package.json': JSON.stringify({
@@ -201,9 +231,8 @@ t.test('workspaces', (t) => {
201231
const pack = new Pack(npm)
202232

203233
t.test('all workspaces', (t) => {
204-
pack.execWorkspaces([], [], er => {
205-
if (er)
206-
throw er
234+
pack.execWorkspaces([], [], err => {
235+
t.error(err, { bail: true })
207236

208237
t.strictSame(OUTPUT, [
209238
['workspace-a-1.0.0.tgz'],
@@ -214,9 +243,8 @@ t.test('workspaces', (t) => {
214243
})
215244

216245
t.test('all workspaces, `.` first arg', (t) => {
217-
pack.execWorkspaces(['.'], [], er => {
218-
if (er)
219-
throw er
246+
pack.execWorkspaces(['.'], [], err => {
247+
t.error(err, { bail: true })
220248

221249
t.strictSame(OUTPUT, [
222250
['workspace-a-1.0.0.tgz'],
@@ -227,9 +255,8 @@ t.test('workspaces', (t) => {
227255
})
228256

229257
t.test('one workspace', (t) => {
230-
pack.execWorkspaces([], ['workspace-a'], er => {
231-
if (er)
232-
throw er
258+
pack.execWorkspaces([], ['workspace-a'], err => {
259+
t.error(err, { bail: true })
233260

234261
t.strictSame(OUTPUT, [
235262
['workspace-a-1.0.0.tgz'],
@@ -239,9 +266,8 @@ t.test('workspaces', (t) => {
239266
})
240267

241268
t.test('specific package', (t) => {
242-
pack.execWorkspaces(['abbrev'], [], er => {
243-
if (er)
244-
throw er
269+
pack.execWorkspaces(['abbrev'], [], err => {
270+
t.error(err, { bail: true })
245271

246272
t.strictSame(OUTPUT, [
247273
['abbrev-1.0.0-test.tgz'],

0 commit comments

Comments
 (0)