mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-24 07:38:12 -05:00
10
.changeset/bright-steaks-cough.md
Normal file
10
.changeset/bright-steaks-cough.md
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
"@pnpm/store-connection-manager": minor
|
||||
"@pnpm/package-requester": minor
|
||||
"@pnpm/plugin-commands-rebuild": minor
|
||||
"@pnpm/package-store": minor
|
||||
"@pnpm/config": minor
|
||||
"pnpm": minor
|
||||
---
|
||||
|
||||
Some registries allow the exact same content to be published under different package names and/or versions. This breaks the validity checks of packages in the store. To avoid errors when verifying the names and versions of such packages in the store, you may now set the `strict-store-pkg-content-check` setting to `false` [#4724](https://github.com/pnpm/pnpm/issues/4724).
|
||||
@@ -195,6 +195,7 @@ export interface Config {
|
||||
packageManagerStrictVersion?: boolean
|
||||
virtualStoreDirMaxLength: number
|
||||
peersSuffixMaxLength?: number
|
||||
strictStorePkgContentCheck: boolean
|
||||
}
|
||||
|
||||
export interface ConfigWithDeprecatedSettings extends Config {
|
||||
|
||||
@@ -133,6 +133,7 @@ export const types = Object.assign({
|
||||
'state-dir': String,
|
||||
'store-dir': String,
|
||||
stream: Boolean,
|
||||
'strict-store-pkg-content-check': Boolean,
|
||||
'strict-peer-dependencies': Boolean,
|
||||
'use-beta-cli': Boolean,
|
||||
'use-node-version': String,
|
||||
@@ -264,6 +265,7 @@ export async function getConfig (
|
||||
symlink: true,
|
||||
'shared-workspace-lockfile': true,
|
||||
'shell-emulator': false,
|
||||
'strict-store-pkg-content-check': true,
|
||||
reverse: false,
|
||||
sort: true,
|
||||
'strict-peer-dependencies': false,
|
||||
|
||||
@@ -49,6 +49,7 @@ export type StrictRebuildOptions = {
|
||||
onlyBuiltDependencies?: string[]
|
||||
virtualStoreDirMaxLength: number
|
||||
peersSuffixMaxLength: number
|
||||
strictStorePkgContentCheck: boolean
|
||||
} & Pick<Config, 'sslConfigs'>
|
||||
|
||||
export type RebuildOptions = Partial<StrictRebuildOptions> &
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
} from '@pnpm/fetcher-base'
|
||||
import { type Cafs } from '@pnpm/cafs-types'
|
||||
import gfs from '@pnpm/graceful-fs'
|
||||
import { logger } from '@pnpm/logger'
|
||||
import { globalWarn, logger } from '@pnpm/logger'
|
||||
import { packageIsInstallable } from '@pnpm/package-is-installable'
|
||||
import { readPackageJson } from '@pnpm/read-package-json'
|
||||
import {
|
||||
@@ -91,6 +91,7 @@ export function createPackageRequester (
|
||||
storeDir: string
|
||||
verifyStoreIntegrity: boolean
|
||||
virtualStoreDirMaxLength: number
|
||||
strictStorePkgContentCheck?: boolean
|
||||
}
|
||||
): RequestPackageFunction & {
|
||||
fetchPackageToStore: FetchPackageToStoreFunction
|
||||
@@ -122,6 +123,7 @@ export function createPackageRequester (
|
||||
}),
|
||||
storeDir: opts.storeDir,
|
||||
virtualStoreDirMaxLength: opts.virtualStoreDirMaxLength,
|
||||
strictStorePkgContentCheck: opts.strictStorePkgContentCheck,
|
||||
})
|
||||
const requestPackage = resolveAndFetch.bind(null, {
|
||||
engineStrict: opts.engineStrict,
|
||||
@@ -342,6 +344,7 @@ function fetchToStore (
|
||||
}
|
||||
storeDir: string
|
||||
virtualStoreDirMaxLength: number
|
||||
strictStorePkgContentCheck?: boolean
|
||||
},
|
||||
opts: FetchPackageToStoreOptions
|
||||
): {
|
||||
@@ -484,10 +487,17 @@ function fetchToStore (
|
||||
!equalOrSemverEqual(pkgFilesIndex.version, opts.expectedPkg.version)
|
||||
)
|
||||
) {
|
||||
throw new PnpmError('UNEXPECTED_PKG_CONTENT_IN_STORE', `\
|
||||
Package name mismatch found while reading ${JSON.stringify(opts.pkg.resolution)} from the store. \
|
||||
This means that the lockfile is broken. Expected package: ${opts.expectedPkg.name}@${opts.expectedPkg.version}. \
|
||||
Actual package in the store by the given integrity: ${pkgFilesIndex.name}@${pkgFilesIndex.version}.`)
|
||||
const msg = `Package name mismatch found while reading ${JSON.stringify(opts.pkg.resolution)} from the store.`
|
||||
const hint = `This means that either the lockfile is broken or the package metadata (name and version) inside the package's package.json file doesn't match the metadata in the registry. \
|
||||
Expected package: ${opts.expectedPkg.name}@${opts.expectedPkg.version}. \
|
||||
Actual package in the store with the given integrity: ${pkgFilesIndex.name}@${pkgFilesIndex.version}.`
|
||||
if (ctx.strictStorePkgContentCheck ?? true) {
|
||||
throw new PnpmError('UNEXPECTED_PKG_CONTENT_IN_STORE', msg, {
|
||||
hint: `${hint}\n\nIf you want to ignore this issue, set the strict-store-pkg-content-check to false.`,
|
||||
})
|
||||
} else {
|
||||
globalWarn(`${msg} ${hint}`)
|
||||
}
|
||||
}
|
||||
fetching.resolve({
|
||||
files: {
|
||||
|
||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -4687,6 +4687,9 @@ importers:
|
||||
'@pnpm/run-npm':
|
||||
specifier: workspace:*
|
||||
version: link:../exec/run-npm
|
||||
'@pnpm/store.cafs':
|
||||
specifier: workspace:*
|
||||
version: link:../store/cafs
|
||||
'@pnpm/tabtab':
|
||||
specifier: ^0.5.3
|
||||
version: 0.5.3
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
"@pnpm/read-project-manifest": "workspace:*",
|
||||
"@pnpm/registry-mock": "3.31.0",
|
||||
"@pnpm/run-npm": "workspace:*",
|
||||
"@pnpm/store.cafs": "workspace:*",
|
||||
"@pnpm/tabtab": "^0.5.3",
|
||||
"@pnpm/test-fixtures": "workspace:*",
|
||||
"@pnpm/test-ipc-server": "workspace:*",
|
||||
|
||||
@@ -5,12 +5,15 @@ import { type Lockfile } from '@pnpm/lockfile-types'
|
||||
import { prepare, prepareEmpty, preparePackages } from '@pnpm/prepare'
|
||||
import { readPackageJsonFromDir } from '@pnpm/read-package-json'
|
||||
import { readProjectManifest } from '@pnpm/read-project-manifest'
|
||||
import { getIntegrity } from '@pnpm/registry-mock'
|
||||
import { getFilePathInCafs } from '@pnpm/store.cafs'
|
||||
import { writeProjectManifest } from '@pnpm/write-project-manifest'
|
||||
import dirIsCaseSensitive from 'dir-is-case-sensitive'
|
||||
import { sync as readYamlFile } from 'read-yaml-file'
|
||||
import { sync as rimraf } from '@zkochan/rimraf'
|
||||
import isWindows from 'is-windows'
|
||||
import loadJsonFile from 'load-json-file'
|
||||
import writeJsonFile from 'write-json-file'
|
||||
import crossSpawn from 'cross-spawn'
|
||||
import {
|
||||
execPnpm,
|
||||
@@ -507,3 +510,27 @@ test('installation fails with a timeout error', async () => {
|
||||
execPnpm(['add', 'typescript@2.4.2', '--fetch-timeout=1', '--fetch-retries=0'])
|
||||
).rejects.toThrow()
|
||||
})
|
||||
|
||||
test('installation fails when the stored package name and version do not match the meta of the installed package', async () => {
|
||||
prepare()
|
||||
const storeDir = path.resolve('store')
|
||||
const settings = [`--config.store-dir=${storeDir}`]
|
||||
|
||||
await execPnpm(['add', '@pnpm.e2e/dep-of-pkg-with-1-dep@100.1.0', ...settings])
|
||||
|
||||
const cafsDir = path.join(storeDir, 'v3/files')
|
||||
const cacheIntegrityPath = getFilePathInCafs(cafsDir, getIntegrity('@pnpm.e2e/dep-of-pkg-with-1-dep', '100.1.0'), 'index')
|
||||
const cacheIntegrity = loadJsonFile.sync<any>(cacheIntegrityPath) // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
cacheIntegrity.name = 'foo'
|
||||
writeJsonFile.sync(cacheIntegrityPath, {
|
||||
...cacheIntegrity,
|
||||
name: 'foo',
|
||||
})
|
||||
|
||||
rimraf('node_modules')
|
||||
await expect(
|
||||
execPnpm(['install', ...settings])
|
||||
).rejects.toThrow()
|
||||
|
||||
await execPnpm(['install', '--config.strict-store-pkg-content-check=false', ...settings])
|
||||
})
|
||||
|
||||
@@ -130,6 +130,9 @@
|
||||
{
|
||||
"path": "../../reviewing/plugin-commands-outdated"
|
||||
},
|
||||
{
|
||||
"path": "../../store/cafs"
|
||||
},
|
||||
{
|
||||
"path": "../../store/plugin-commands-server"
|
||||
},
|
||||
|
||||
@@ -133,6 +133,9 @@
|
||||
{
|
||||
"path": "../reviewing/plugin-commands-outdated"
|
||||
},
|
||||
{
|
||||
"path": "../store/cafs"
|
||||
},
|
||||
{
|
||||
"path": "../store/plugin-commands-server"
|
||||
},
|
||||
|
||||
@@ -28,6 +28,7 @@ export function createPackageStore (
|
||||
packageImportMethod?: 'auto' | 'hardlink' | 'copy' | 'clone' | 'clone-or-copy'
|
||||
verifyStoreIntegrity: boolean
|
||||
virtualStoreDirMaxLength: number
|
||||
strictStorePkgContentCheck?: boolean
|
||||
clearResolutionCache: () => void
|
||||
}
|
||||
): StoreController {
|
||||
@@ -49,6 +50,7 @@ export function createPackageStore (
|
||||
storeDir: initOpts.storeDir,
|
||||
verifyStoreIntegrity: initOpts.verifyStoreIntegrity,
|
||||
virtualStoreDirMaxLength: initOpts.virtualStoreDirMaxLength,
|
||||
strictStorePkgContentCheck: initOpts.strictStorePkgContentCheck,
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
@@ -45,7 +45,7 @@ export type CreateNewStoreControllerOptions = CreateResolverOptions & Pick<Confi
|
||||
> & {
|
||||
cafsLocker?: CafsLocker
|
||||
ignoreFile?: (filename: string) => boolean
|
||||
} & Partial<Pick<Config, 'userConfig' | 'deployAllFiles' | 'sslConfigs'>> & Pick<ClientOptions, 'resolveSymlinksInInjectedDirs'>
|
||||
} & Partial<Pick<Config, 'userConfig' | 'deployAllFiles' | 'sslConfigs' | 'strictStorePkgContentCheck'>> & Pick<ClientOptions, 'resolveSymlinksInInjectedDirs'>
|
||||
|
||||
export async function createNewStoreController (
|
||||
opts: CreateNewStoreControllerOptions
|
||||
@@ -107,6 +107,7 @@ export async function createNewStoreController (
|
||||
? opts.verifyStoreIntegrity
|
||||
: true,
|
||||
virtualStoreDirMaxLength: opts.virtualStoreDirMaxLength,
|
||||
strictStorePkgContentCheck: opts.strictStorePkgContentCheck,
|
||||
clearResolutionCache,
|
||||
}),
|
||||
dir: opts.storeDir,
|
||||
|
||||
Reference in New Issue
Block a user