fix: stop setting npm_config_ env vars during lifecycle scripts (#11116)

* fix: stop setting npm_config_ env vars from pnpm config during lifecycle scripts

Update @pnpm/npm-lifecycle to 1100.0.0-0 which no longer dumps the
entire pnpm config as npm_config_* environment variables. This fixes
npm warnings about unknown config when lifecycle scripts invoke npm.

Only well-known npm_* env vars are now set, matching Yarn's behavior.

* fix: fix spellcheck in changeset

* chore: remove obsolete @pnpm/npm-lifecycle patch file

* fix: pass npm_config_user_agent via extraEnv in lifecycle scripts

The npm-lifecycle makeEnv() strips all npm_* vars from process.env,
so npm_config_user_agent must be explicitly passed via extraEnv.

* chore: mark changeset as major (breaking change)
This commit is contained in:
Zoltan Kochan
2026-03-27 19:02:07 +01:00
committed by GitHub
parent d3d6938414
commit 366cabeec8
7 changed files with 36 additions and 30 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/exec.lifecycle": major
"pnpm": major
---
Stop setting `npm_config_*` environment variables from pnpm config during lifecycle scripts. This fixes `npm warn Unknown env config` warnings when lifecycle scripts invoke npm internally. Only well-known `npm_*` env vars (like `npm_lifecycle_event`, `npm_config_node_gyp`, `npm_config_user_agent`, etc.) are now set, matching Yarn's behavior.

View File

@@ -1,13 +0,0 @@
diff --git a/index.js b/index.js
index 8506b4c43670dd8ddb490001f2c2a5649b11f326..af35d94765e23a4e9b46b0e332ffd37061e05968 100644
--- a/index.js
+++ b/index.js
@@ -87,7 +87,7 @@ function lifecycle (pkg, stage, wd, opts) {
// Instead, we use the path to the exe file.
env.npm_execpath = process.execPath
} else {
- env.npm_execpath = require.main ? require.main.filename : process.cwd()
+ env.npm_execpath = process.argv[1] ?? process.cwd()
}
env.INIT_CWD = process.cwd()
env.npm_config_node_gyp = env.npm_config_node_gyp || DEFAULT_NODE_GYP_PATH

View File

@@ -39,8 +39,8 @@ declare module '@pnpm/npm-conf/lib/conf' {
}
declare module '@pnpm/npm-lifecycle' {
const anything: any
export = anything
export function lifecycle (pkg: any, stage: string, wd: string, opts: any): Promise<void>
export function makeEnv (data: any, opts: any, prefix?: string | null, env?: any): Record<string, string>
}
declare module '@pnpm/npm-package-arg' {

View File

@@ -4,7 +4,7 @@ import path from 'node:path'
import { lifecycleLogger } from '@pnpm/core-loggers'
import { PnpmError } from '@pnpm/error'
import { globalWarn } from '@pnpm/logger'
import lifecycle from '@pnpm/npm-lifecycle'
import { lifecycle } from '@pnpm/npm-lifecycle'
import type { DependencyManifest, PackageScripts, ProjectManifest } from '@pnpm/types'
import isWindows from 'is-windows'
import { join as shellQuote } from 'shlex'
@@ -110,16 +110,14 @@ Please unset the scriptShell option, or configure it to a .exe instead.
? 'silent'
: undefined
await lifecycle(m, stage, opts.pkgRoot, {
config: {
...opts.rawConfig,
'frozen-lockfile': false,
},
config: {},
dir: opts.rootModulesDir,
extraBinPaths: opts.extraBinPaths,
extraEnv: {
...opts.extraEnv,
INIT_CWD: opts.initCwd ?? process.cwd(),
PNPM_SCRIPT_SRC_DIR: opts.pkgRoot,
...('user-agent' in opts.rawConfig ? { npm_config_user_agent: (opts.rawConfig as Record<string, string>)['user-agent'] } : {}),
},
log: {
clearProgress: noop,

View File

@@ -64,7 +64,7 @@ test('runLifecycleHook() passes newline correctly', async () => {
])
})
test('runLifecycleHook() sets frozen-lockfile to false', async () => {
test('runLifecycleHook() does not set npm_config env vars', async () => {
const pkgRoot = f.find('inspect-frozen-lockfile')
await using server = await createTestIpcServer(path.join(pkgRoot, 'test.sock'))
const { default: pkg } = await import(path.join(pkgRoot, 'package.json'))
@@ -78,7 +78,7 @@ test('runLifecycleHook() sets frozen-lockfile to false', async () => {
unsafePerm: true,
})
expect(server.getLines()).toStrictEqual(['empty string'])
expect(server.getLines()).toStrictEqual(['unset'])
})
test('runPostinstallHooks()', async () => {

28
pnpm-lock.yaml generated
View File

@@ -251,8 +251,8 @@ catalogs:
specifier: 3.0.2
version: 3.0.2
'@pnpm/npm-lifecycle':
specifier: ^1001.0.0
version: 1001.0.0
specifier: 1100.0.0-0
version: 1100.0.0-0
'@pnpm/npm-package-arg':
specifier: ^2.0.0
version: 2.0.0
@@ -980,7 +980,6 @@ packageExtensionsChecksum: sha256-87FOGilaYY8gmnjYsryuV/BI3ZuhaaJd/1fN2oxQwzY=
pnpmfileChecksum: sha256-FyKtfMeHqu9zq1rXAr8P3zdA0NAXUioGdY0esg+SB5s=
patchedDependencies:
'@pnpm/npm-lifecycle': 9ca23edf604c5e8ff290e3c0a5443646b5f9865624042a5c41d9b2beb8f98972
graceful-fs@4.2.11: 68ebc232025360cb3dcd3081f4067f4e9fc022ab6b6f71a3230e86c7a5b337d1
importers:
@@ -4021,7 +4020,7 @@ importers:
version: link:../../fetching/directory-fetcher
'@pnpm/npm-lifecycle':
specifier: 'catalog:'
version: 1001.0.0(patch_hash=9ca23edf604c5e8ff290e3c0a5443646b5f9865624042a5c41d9b2beb8f98972)(typanion@3.14.0)
version: 1100.0.0-0(typanion@3.14.0)
'@pnpm/pkg-manifest.reader':
specifier: workspace:*
version: link:../../pkg-manifest/reader
@@ -10627,6 +10626,10 @@ packages:
resolution: {integrity: sha512-5jW/GNLdZMiw+PJ8FYSvOghoApSjsORNIro2fj8j6NHAqJxJjcHekC5/NsKaawoI5LAkU/XDDVjNC71Yz+uS1w==}
engines: {node: '>=18.12'}
'@pnpm/npm-lifecycle@1100.0.0-0':
resolution: {integrity: sha512-FymJ23SU6f3AlgUsK0Bt+0ztIWe3MFkqGbPL86couBb37fH+UNyG6P6IUmOv/lXA4Y2mhqGDTSV0/8mYI08xng==}
engines: {node: '>=22.13'}
'@pnpm/npm-package-arg@2.0.0':
resolution: {integrity: sha512-429x8dFMgxZoeYUTUPAMC09IeM5yQ86X1LyYEQF1P4uyvhLSCh44QKkiprX9qdwBsV9QxjeNad2QoDZy1RSeRw==}
engines: {node: '>=18.12'}
@@ -18345,7 +18348,7 @@ snapshots:
'@pnpm/error': 1000.1.0
'@pnpm/link-bins': 1000.3.8(@pnpm/logger@1001.0.1)
'@pnpm/logger': 1001.0.1
'@pnpm/npm-lifecycle': 1001.0.0(patch_hash=9ca23edf604c5e8ff290e3c0a5443646b5f9865624042a5c41d9b2beb8f98972)(typanion@3.14.0)
'@pnpm/npm-lifecycle': 1001.0.0(typanion@3.14.0)
'@pnpm/read-package-json': 1000.1.8
'@pnpm/store-controller-types': 1004.5.1
'@pnpm/types': 1001.3.0
@@ -18515,7 +18518,7 @@ snapshots:
'@pnpm/network.ca-file': 1.0.2
config-chain: 1.1.13
'@pnpm/npm-lifecycle@1001.0.0(patch_hash=9ca23edf604c5e8ff290e3c0a5443646b5f9865624042a5c41d9b2beb8f98972)(typanion@3.14.0)':
'@pnpm/npm-lifecycle@1001.0.0(typanion@3.14.0)':
dependencies:
'@pnpm/byline': 1.0.0
'@pnpm/error': 1000.1.0
@@ -18531,6 +18534,19 @@ snapshots:
- supports-color
- typanion
'@pnpm/npm-lifecycle@1100.0.0-0(typanion@3.14.0)':
dependencies:
'@pnpm/byline': 1.0.0
'@pnpm/error': 1000.1.0
'@yarnpkg/fslib': 3.1.5
'@yarnpkg/shell': 4.0.0(typanion@3.14.0)
node-gyp: 11.5.0
uid-number: 0.0.6
which: 4.0.0
transitivePeerDependencies:
- supports-color
- typanion
'@pnpm/npm-package-arg@2.0.0':
dependencies:
hosted-git-info: 4.1.0

View File

@@ -89,7 +89,7 @@ catalog:
'@pnpm/network.agent': ^2.0.3
'@pnpm/nopt': ^0.3.1
'@pnpm/npm-conf': 3.0.2
'@pnpm/npm-lifecycle': ^1001.0.0
'@pnpm/npm-lifecycle': 1100.0.0-0
'@pnpm/npm-package-arg': ^2.0.0
'@pnpm/os.env.path-extender': ^3.0.0
'@pnpm/patch-package': 0.0.1
@@ -463,7 +463,6 @@ packageExtensions:
unified: '*'
patchedDependencies:
'@pnpm/npm-lifecycle': __patches__/@pnpm__npm-lifecycle.patch
graceful-fs@4.2.11: __patches__/graceful-fs@4.2.11.patch
patchesDir: __patches__