yarn run adds random folders to PATH

Bug description

Command

yarn run something

What is the current behavior?

something is executed with an environment that has random folders prepended to PATH. The prepending happens here:

pathParts.unshift(path.join(path.dirname(process.execPath), ‘node_modules’, ‘npm’, ‘bin’, ‘node-gyp-bin’));
pathParts.unshift(
path.join(path.dirname(process.execPath), ‘..’, ‘lib’, ‘node_modules’, ‘npm’, ‘bin’, ‘node-gyp-bin’),
);
// Include node-gyp version from homebrew managed npm, if available.
pathParts.unshift(
path.join(path.dirname(process.execPath), ‘..’, ‘libexec’, ‘lib’, ‘node_modules’, ‘npm’, ‘bin’, ‘node-gyp-bin’),
);
// Add global bin folder if it is not present already, as some packages depend
// on a globally-installed version of node-gyp.
const globalBin = await getGlobalBinFolder(config, {});
if (pathParts.indexOf(globalBin) === -1) {
pathParts.unshift(globalBin);
}
// Add node_modules .bin folders to the PATH
for (const registryFolder of config.registryFolders) {
const binFolder = path.join(registryFolder, ‘.bin’);
if (config.workspacesEnabled && config.workspaceRootFolder) {
pathParts.unshift(path.join(config.workspaceRootFolder, binFolder));
}
pathParts.unshift(path.join(config.linkFolder, binFolder));
pathParts.unshift(path.join(cwd, binFolder));
}
let pnpFile;
if (process.versions.pnp) {
pnpFile = dynamicRequire.resolve(‘pnpapi’);
} else {
const candidate = `${config.lockfileFolder}/${constants.PNP_FILENAME}`;
if (await fs.exists(candidate)) {
pnpFile = candidate;
}
}
if (pnpFile) {
const pnpApi = dynamicRequire(pnpFile);
const packageLocator = pnpApi.findPackageLocator(`${cwd}/`);
const packageInformation = pnpApi.getPackageInformation(packageLocator);
for (const [name, reference] of packageInformation.packageDependencies.entries()) {
const dependencyInformation = pnpApi.getPackageInformation({name, reference});
if (!dependencyInformation || !dependencyInformation.packageLocation) {
continue;
}
const binFolder = `${dependencyInformation.packageLocation}/.bin`;
if (await fs.exists(binFolder)) {
pathParts.unshift(binFolder);
}
}
// Note that NODE_OPTIONS doesn’t support any style of quoting its arguments at the moment
// For this reason, it won’t work if the user has a space inside its $PATH
env.NODE_OPTIONS = env.NODE_OPTIONS || ”;
env.NODE_OPTIONS = `–require ${pnpFile} ${env.NODE_OPTIONS}`;
}
pathParts.unshift(await getWrappersFolder(config));

The worst offender being

pathParts.unshift(globalBin);

This can potentially cause wrong programs to be executed if there are multiple versions installed, with no way to configure this behaviour.

What is the expected behavior?

Run commands with unmodified environment, or make overriding behaviour configurable

Steps to Reproduce

mkdir -p /tmp/a
cat > /tmp/a/package.json <<EOF
{
  "scripts": {
    "something": "echo \$PATH"
  }
}
EOF
echo "$PATH"
(cd /tmp/a && yarn run something) # != PATH

Environment

  • Node Version: v12.15.0
  • Yarn v1 Version: 1.22
  • OS and version: arch linux kernel 5.9.10-arch1-1

Author: Fantashit

1 thought on “yarn run adds random folders to PATH

Comments are closed.