fix: warn when directory contains PATH delimiter character (#10487)

* fix: warn when directory contains PATH delimiter character

Add a warning when the current directory contains the PATH delimiter
character (colon on macOS/Linux, semicolon on Windows). On macOS,
folder names containing forward slashes (/) appear as colons (:) at
the Unix layer. Since colons are PATH separators in POSIX systems,
this breaks PATH injection for node_modules/.bin.

close #10457

* test: add tests for PATH delimiter warning

- Test warning is emitted when directory contains delimiter
- Test no warning for normal directories
This commit is contained in:
Dennis Chen
2026-02-06 23:04:19 +08:00
committed by GitHub
parent 3cfffaad10
commit 559f903a90
3 changed files with 57 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
---
"@pnpm/config": patch
"pnpm": patch
---
Add a warning when the current directory contains the PATH delimiter character. On macOS, folder names containing forward slashes (/) appear as colons (:) at the Unix layer. Since colons are PATH separators in POSIX systems, this breaks PATH injection for `node_modules/.bin`, causing binaries to not be found when running commands like `pnpm exec`.
Closes [#10457](https://github.com/pnpm/pnpm/issues/10457).

View File

@@ -274,6 +274,12 @@ export async function getConfig (opts: {
// This prevents potential inconsistencies in the future, especially when processing or mapping subdirectories.
const cwd = fs.realpathSync(betterPathResolve(cliOptions.dir ?? npmConfig.localPrefix))
// Unfortunately, there is no way to escape the PATH delimiter,
// so directories added to PATH should not contain it.
if (cwd.includes(path.delimiter)) {
warnings.push(`Directory "${cwd}" contains the path delimiter character (${path.delimiter}), so binaries from node_modules/.bin will not be accessible via PATH. Consider renaming the directory.`)
}
pnpmConfig.maxSockets = npmConfig.maxsockets
// @ts-expect-error
delete pnpmConfig['maxsockets']

View File

@@ -1,5 +1,6 @@
/// <reference path="../../../__typings__/index.d.ts"/>
import fs from 'fs'
import os from 'os'
import path from 'path'
import PATH from 'path-name'
import { sync as writeYamlFile } from 'write-yaml-file'
@@ -1361,6 +1362,48 @@ test('CLI should override environment variable pnpm_config_*', async () => {
})).toBe(10)
})
test('warn when directory contains PATH delimiter character', async () => {
const tempDir = path.join(os.tmpdir(), `pnpm-test${path.delimiter}project-${Date.now()}`)
fs.mkdirSync(tempDir, { recursive: true })
try {
const { warnings } = await getConfig({
cliOptions: { dir: tempDir },
packageManager: {
name: 'pnpm',
version: '1.0.0',
},
})
expect(warnings).toContainEqual(
expect.stringContaining('path delimiter character')
)
} finally {
fs.rmSync(tempDir, { recursive: true })
}
})
test('no warning when directory does not contain PATH delimiter character', async () => {
const tempDir = path.join(os.tmpdir(), `pnpm-test-normal-${Date.now()}`)
fs.mkdirSync(tempDir, { recursive: true })
try {
const { warnings } = await getConfig({
cliOptions: { dir: tempDir },
packageManager: {
name: 'pnpm',
version: '1.0.0',
},
})
expect(warnings).not.toContainEqual(
expect.stringContaining('path delimiter character')
)
} finally {
fs.rmSync(tempDir, { recursive: true })
}
})
describe('global config.yaml', () => {
let XDG_CONFIG_HOME: string | undefined