diff --git a/installing/commands/package.json b/installing/commands/package.json index d8cb8beaab..4e067093c5 100644 --- a/installing/commands/package.json +++ b/installing/commands/package.json @@ -88,6 +88,7 @@ "@zkochan/table": "catalog:", "chalk": "catalog:", "ci-info": "catalog:", + "detect-libc": "catalog:", "get-npm-tarball-url": "catalog:", "is-subdir": "catalog:", "load-json-file": "catalog:", diff --git a/installing/commands/src/runPacquet.ts b/installing/commands/src/runPacquet.ts index 8ab582fe00..80375f7511 100644 --- a/installing/commands/src/runPacquet.ts +++ b/installing/commands/src/runPacquet.ts @@ -8,6 +8,7 @@ import type { Writable } from 'node:stream' import { PnpmError } from '@pnpm/error' import { logger, streamParser } from '@pnpm/logger' import chalk from 'chalk' +import { familySync as getLibcFamilySync, MUSL } from 'detect-libc' // The runtime `streamParser` is a `Transform` stream (split2 + JSON.parse). // Its public typing only exposes `on`/`removeListener`, so we narrow to the @@ -178,7 +179,18 @@ export function makeRunPacquet (opts: MakeRunPacquetOpts): (callOpts?: RunPacque function resolvePacquetBin (lockfileDir: string, packageName: 'pacquet' | '@pnpm/pacquet'): string { const ext = process.platform === 'win32' ? '.exe' : '' const pacquetPkg = fs.realpathSync(path.join(lockfileDir, 'node_modules/.pnpm-config', packageName, 'package.json')) - return createRequire(pacquetPkg).resolve(`@pacquet/${process.platform}-${process.arch}/pacquet${ext}`) + return createRequire(pacquetPkg).resolve(`${pacquetPlatformPkgName()}/pacquet${ext}`) +} + +/** + * Name of the `@pacquet/-[-musl]` package that holds the + * native pacquet binary for the host. On linux the binary packages are + * split by libc and only the matching one is installed, so spawning and + * signature verification must agree on this exact name. + */ +export function pacquetPlatformPkgName (): string { + const libc = process.platform === 'linux' && getLibcFamilySync() === MUSL ? '-musl' : '' + return `@pacquet/${process.platform}-${process.arch}${libc}` } /** diff --git a/installing/commands/src/verifyPacquetIdentity.ts b/installing/commands/src/verifyPacquetIdentity.ts index accefd808c..30ec3ee266 100644 --- a/installing/commands/src/verifyPacquetIdentity.ts +++ b/installing/commands/src/verifyPacquetIdentity.ts @@ -11,6 +11,8 @@ import { createGetAuthHeaderByURI } from '@pnpm/network.auth-header' import type { CreateFetchFromRegistryOptions, RetryTimeoutOptions } from '@pnpm/network.fetch' import type { Registries, RegistryConfig } from '@pnpm/types' +import { pacquetPlatformPkgName } from './runPacquet.js' + export interface VerifyPacquetIdentityOptions extends CreateFetchFromRegistryOptions { lockfileDir: string rootDir: string @@ -93,7 +95,7 @@ async function collectPacquetPackagesToVerify ( // Only the host's platform binary is ever spawned, so that's the one whose // identity matters. If it isn't in the lockfile, pacquet couldn't run here. - const platformPkgName = `@pacquet/${process.platform}-${process.arch}` + const platformPkgName = pacquetPlatformPkgName() const platformVersion = envLockfile.snapshots[shimKey]?.optionalDependencies?.[platformPkgName] if (platformVersion == null) return undefined const platformKey = `${platformPkgName}@${platformVersion}` diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8442b546ee..113a9ceace 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5399,6 +5399,9 @@ importers: ci-info: specifier: 'catalog:' version: 4.4.0 + detect-libc: + specifier: 'catalog:' + version: 2.1.2 get-npm-tarball-url: specifier: 'catalog:' version: 2.1.0