fix(npm-resolver): throw a meaningful error on malformed meta

close #3013
PR #3019
This commit is contained in:
Zoltan Kochan
2020-12-12 20:37:47 +02:00
committed by GitHub
parent a1c9cd2316
commit f47551a3c9
4 changed files with 75 additions and 21 deletions

View File

@@ -0,0 +1,5 @@
---
"@pnpm/npm-resolver": patch
---
Throw a meaningful error on malformed registry metadata.

View File

@@ -1,3 +1,4 @@
import PnpmError from '@pnpm/error'
import { VersionSelectors } from '@pnpm/resolver-base'
import { RegistryPackageSpec } from './parsePref'
import { PackageInRegistry, PackageMeta } from './pickPackage'
@@ -8,28 +9,35 @@ export default function (
preferredVersionSelectors: VersionSelectors | undefined,
meta: PackageMeta
): PackageInRegistry {
let version!: string
switch (spec.type) {
case 'version':
version = spec.fetchSpec
break
case 'tag':
version = meta['dist-tags'][spec.fetchSpec]
break
case 'range':
version = pickVersionByVersionRange(meta, spec.fetchSpec, preferredVersionSelectors)
break
try {
let version!: string
switch (spec.type) {
case 'version':
version = spec.fetchSpec
break
case 'tag':
version = meta['dist-tags'][spec.fetchSpec]
break
case 'range':
version = pickVersionByVersionRange(meta, spec.fetchSpec, preferredVersionSelectors)
break
}
const manifest = meta.versions[version]
if (manifest && meta['name']) {
// Packages that are published to the GitHub registry are always published with a scope.
// However, the name in the package.json for some reason may omit the scope.
// So the package published to the GitHub registry will be published under @foo/bar
// but the name in package.json will be just bar.
// In order to avoid issues, we consider that the real name of the package is the one with the scope.
manifest.name = meta['name']
}
return manifest
} catch (err) {
throw new PnpmError('MALFORMED_METADATA',
`Received malformed metadata for "${spec.name}"`,
{ hint: 'This might mean that the package was unpublished from the registry' }
)
}
const manifest = meta.versions[version]
if (manifest && meta['name']) {
// Packages that are published to the GitHub registry are always published with a scope.
// However, the name in the package.json for some reason may omit the scope.
// So the package published to the GitHub registry will be published under @foo/bar
// but the name in package.json will be just bar.
// In order to avoid issues, we consider that the real name of the package is the one with the scope.
manifest.name = meta['name']
}
return manifest
}
function pickVersionByVersionRange (

View File

@@ -1535,3 +1535,17 @@ test('request to metadata is retried if the received JSON is broken', async () =
expect(resolveResult?.id).toBe('registry.npmjs.org/is-positive/1.0.0')
})
test('request to a package with malformed metadata', async () => {
nock(registry)
.get('/code-snippet')
.reply(200, loadJsonFile.sync(path.join(__dirname, 'meta/malformed.json')))
const storeDir = tempy.directory()
const resolve = createResolveFromNpm({ storeDir })
await expect(resolve({ alias: 'code-snippet' }, { registry })).rejects
.toThrow(
new PnpmError('MALFORMED_METADATA', 'Received malformed metadata for "code-snippet"')
)
})

View File

@@ -0,0 +1,27 @@
{
"_id": "code-snippet",
"_rev": "2-b2defd889997bf20ca640c1a9b38d82c",
"name": "code-snippet",
"time": {
"modified": "2015-07-31T03:43:17.076Z",
"created": "2015-07-31T03:43:17.076Z",
"1.0.4": "2015-07-31T03:43:17.076Z",
"unpublished": {
"name": "nhnent",
"time": "2015-07-31T03:52:16.267Z",
"tags": {
"latest": "1.0.4"
},
"maintainers": [
{
"name": "nhnent",
"email": "dl_javascript@nhnent.com"
}
],
"versions": [
"1.0.4"
]
}
},
"_attachments": {}
}