[Bug?]: `yarn workspace … run` allows running binaries not listed in dependencies (`nodeLinker: node-modules`)
Self-service
- [ ] I'd be willing to implement a fix
Describe the bug
When running binaries in a workspace, it's possible for yarn to incorrectly determine that the binary is available and execute. This can happen when a workspace script is executed via a root script, and that root package.json has a dependency that provides the binary being run.
I ran into this problem when using nx, and having a yarn nx entry point that we use to execute commands in other workspaces. The problem came about where we had a dependency on eslint in our root package.json, but had missed it in our workspace package.json, and encountered unexpected difference in behavior where yarn nx build lib worked, but yarn workspace lib build did not.
This seems to be because of $PATH inheritance via environment, where the parent yarn process adds binaries to a temp directory and puts it on $PATH, and then the child yarn inherits that and sees binaries that it shouldn't.
To reproduce
const fs = require('fs').promises;
await fs.writeFile('.yarnrc.yml', 'nodeLinker: node-modules');
await fs.mkdir('packages/lib', { recursive: true });
await fs.writeFile("packages/lib/package.json", `{
"name": "lib",
"scripts": {
"env": "envinfo"
}
}`);
await packageJsonAndInstall({
"name": "root",
"workspaces": [
"packages/*"
],
"scripts": {
"libEnvViaRoot": "yarn workspace lib env"
},
"dependencies": {
"envinfo": "^7"
},
});
await expect(yarn(`workspace`, `lib`, `bin`, `envinfo`)).rejects.toThrow();
await expect(yarn(`bin`, `envinfo`)).resolves.toBeTruthy();
await expect(yarn(`workspace`, `lib`, `env`)).rejects.toThrow(`command not found: envinfo`);
// This incorrectly succeeds.
await expect(yarn(`libEnvViaRoot`)).rejects.toThrow(`command not found: envinfo`);
Environment
System:
OS: macOS 12.6
CPU: (10) arm64 Apple M1 Max
Binaries:
Node: 16.14.0 - /private/var/folders/jq/3x3ddtjx3rb9nwy79zxfwnj00000gn/T/xfs-ef47ac84/node
Yarn: 3.2.4 - /private/var/folders/jq/3x3ddtjx3rb9nwy79zxfwnj00000gn/T/xfs-ef47ac84/yarn
npm: 8.3.1 - ~/.n/bin/npm
npmPackages:
jest: ^26.6.3 => 26.6.3
Additional context
No response
This issue reproduces on master:
Error: expect(received).rejects.toThrow()
Received promise resolved instead of rejected
Resolved to value: "
System:
OS: Linux 5.15 Alpine Linux
CPU: (2) x64 Intel(R) Xeon(R) Platinum 8272CL CPU @ 2.60GHz
Memory: 4.97 GB / 6.78 GB
Container: Yes
Shell: 1.34.1 - /bin/ash
Binaries:
Node: 16.17.1 - /tmp/xfs-c757b612/node
Yarn: 4.0.0-rc.27.dev - /tmp/xfs-c757b612/yarn
Utilities:
Make: 4.3 - /usr/bin/make
GCC: 12.2.1 - /usr/bin/gcc
Git: 2.34.5 - /usr/bin/git
Languages:
Bash: 5.1.16 - /bin/bash
Perl: 5.36.0 - /usr/bin/perl
Python: 2.7.18 - /usr/bin/python
"
at expect (/github/workspace/.yarn/cache/expect-npm-24.8.0-8c7640c562-44ff9ab1e7.zip/node_modules/expect/build/index.js:138:15)
at module.exports (evalmachine.<anonymous>:30:7)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async /github/workspace/.yarn/cache/@arcanis-sherlock-npm-2.0.3-558f52b79f-286d94b96d.zip/node_modules/@arcanis/sherlock/lib/executeRepro.js:57:13
at async executeInTempDirectory (/github/workspace/.yarn/cache/@arcanis-sherlock-npm-2.0.3-558f52b79f-286d94b96d.zip/node_modules/@arcanis/sherlock/lib/executeRepro.js:18:16)
at async executeRepro (/github/workspace/.yarn/cache/@arcanis-sherlock-npm-2.0.3-558f52b79f-286d94b96d.zip/node_modules/@arcanis/sherlock/lib/executeRepro.js:25:12)
at async ExecCommand.execute (/github/workspace/.yarn/cache/@arcanis-sherlock-npm-2.0.3-558f52b79f-286d94b96d.zip/node_modules/@arcanis/sherlock/lib/commands/exec.js:26:38)
at async ExecCommand.validateAndExecute (/github/workspace/.yarn/cache/clipanion-npm-2.0.0-rc.16-b9444aaf89-4061026d74.zip/node_modules/clipanion/lib/advanced/Command.js:161:26)
at async Cli.run (/github/workspace/.yarn/cache/clipanion-npm-2.0.0-rc.16-b9444aaf89-4061026d74.zip/node_modules/clipanion/lib/advanced/Cli.js:74:24)
at async Cli.runExit (/github/workspace/.yarn/cache/clipanion-npm-2.0.0-rc.16-b9444aaf89-4061026d74.zip/node_modules/clipanion/lib/advanced/Cli.js:83:28)
@bradleyayers Thanks, if you have time and willing to help, you can clone berry repo, create the project that reproduces the error in any directory, then put .yarnrc.yml inside this project and set yarnPath: ../berry/scripts/run-yarn.js inside. After that you can console.log inside berry code and find out where the problem is, your changes into source code will have immediate effect because berry/scripts/run-yarn.js transpiles code on the fly. You can also ask questions on our discord at:
https://discord.com/invite/yarnpkg
The issue reproduces for PnP as well, i.e. not a node-modules linker specifc