Skip to content

Commit 3225fa3

Browse files
authored
fix: fix usage of path of custom registry (#8737)
Properly handle the resolution of a path via a custom registry with a path element in the URL, when the path element is a prefix of a package name. When a custom registry with a path element is used (e.g. http://localhost:3080/npm/), then the resolution of download URLs for packages starting with the path element (in this case `npm`, so e.g. `npm-run-path`) will fail as the path element gets omitted. ## References Fixes #8736
1 parent ca53c21 commit 3225fa3

File tree

2 files changed

+67
-3
lines changed

2 files changed

+67
-3
lines changed

workspaces/arborist/lib/arborist/reify.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -813,9 +813,17 @@ module.exports = cls => class Reifier extends cls {
813813
// Make sure we don't double-include the path if it's already there
814814
const registryPath = registryURL.pathname.replace(/\/$/, '')
815815

816-
if (registryPath && registryPath !== '/' && !resolvedURL.pathname.startsWith(registryPath)) {
817-
// Since hostname is changed, we need to ensure the registry path is included
818-
resolvedURL.pathname = registryPath + resolvedURL.pathname
816+
if (registryPath && registryPath !== '/') {
817+
// Check if the resolved pathname already starts with the registry path
818+
// We need to ensure it's a proper path prefix, not just a string prefix
819+
// e.g., registry path '/npm' should not match '/npm-run-path'
820+
const hasRegistryPath = resolvedURL.pathname === registryPath ||
821+
resolvedURL.pathname.startsWith(registryPath + '/')
822+
823+
if (!hasRegistryPath) {
824+
// Since hostname is changed, we need to ensure the registry path is included
825+
resolvedURL.pathname = registryPath + resolvedURL.pathname
826+
}
819827
}
820828

821829
return resolvedURL.toString()

workspaces/arborist/test/arborist/reify.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3617,6 +3617,62 @@ t.test('should preserve exact ranges, missing actual tree', async (t) => {
36173617
await t.resolves(arb.reify(), 'reify should complete successfully')
36183618
})
36193619

3620+
t.test('registry path prepending with registry path being a package name prefix', async t => {
3621+
// A registry path is prepended to resolved URLs that don't already have it
3622+
const abbrevPackument4 = JSON.stringify({
3623+
_id: 'abbrev',
3624+
_rev: 'lkjadflkjasdf',
3625+
name: 'abbrev',
3626+
'dist-tags': { latest: '1.1.1' },
3627+
versions: {
3628+
'1.1.1': {
3629+
name: 'abbrev',
3630+
version: '1.1.1',
3631+
dist: {
3632+
// Note: This URL has no path component that matches our registry path
3633+
tarball: 'https://external-registry.example.com/abbrev-1.1.1.tgz',
3634+
},
3635+
},
3636+
},
3637+
})
3638+
3639+
const testdir = t.testdir({
3640+
project: {
3641+
'package.json': JSON.stringify({
3642+
name: 'myproject',
3643+
version: '1.0.0',
3644+
dependencies: {
3645+
abbrev: '1.1.1',
3646+
},
3647+
}),
3648+
},
3649+
})
3650+
3651+
// Set up the registry with a deep path
3652+
const registryHost = 'https://registry.example.com'
3653+
// Note: This path is a prefix of the package name 'abbrev'
3654+
const registryPath = '/abb'
3655+
const registry = `${registryHost}${registryPath}`
3656+
3657+
tnock(t, registryHost)
3658+
.get(`${registryPath}/abbrev`)
3659+
.reply(200, abbrevPackument4)
3660+
3661+
// This is the critical test - the tarball URL in the packument doesn't have our registry path, but when replaceRegistryHost is 'always', we should get a request to this URL which includes the registry path
3662+
tnock(t, registryHost)
3663+
.get(`${registryPath}/abbrev-1.1.1.tgz`)
3664+
.reply(200, abbrevTGZ)
3665+
3666+
const arb = new Arborist({
3667+
path: resolve(testdir, 'project'),
3668+
registry,
3669+
cache: resolve(testdir, 'cache'),
3670+
replaceRegistryHost: 'always',
3671+
})
3672+
3673+
await t.resolves(arb.reify(), 'reify should complete successfully')
3674+
})
3675+
36203676
t.test('registry with different protocol should swap protocol', async (t) => {
36213677
const abbrevPackument4 = JSON.stringify({
36223678
_id: 'abbrev',

0 commit comments

Comments
 (0)