build: use the shared pnpm store on Windows by default (#30565)

Without the symlink privilege pnpm links the global virtual store with junctions,
which standard users can create. Verified on Windows 10.0.26200 at medium
integrity with no SeCreateSymbolicLinkPrivilege and Developer Mode off: the
install, both native runtime checks, a ConPTY spawn and windows-process-tree all
pass. ORCA_PNPM_GLOBAL_VIRTUAL_STORE=0 still opts out; CI stays off.
This commit is contained in:
Neil
2026-10-18 22:32:45 -07:00
committed by GitHub
parent 3051b7b671
commit 07bf286c7b
4 changed files with 26 additions and 33 deletions
+5 -5
View File
@@ -37,12 +37,12 @@ In PowerShell, use `$env:ORCA_DEV_MAIN_SOURCEMAPS='0'` before `pnpm dev`.
Remove the variable when debugging the main process with source maps. Renderer and
preload settings are unaffected; production builds always keep their hidden main maps.
On macOS and Linux, installs use pnpm's global virtual store: each package version is one slot
Local installs use pnpm's global virtual store: each package version is one slot
under `~/pnpm/store` that every worktree links to, instead of a full `node_modules` per worktree.
An existing worktree converts on its next `pnpm install`, and an older branch without the setting
converts back the same way. CI always uses the normal layout. Windows does too unless you set
`ORCA_PNPM_GLOBAL_VIRTUAL_STORE=1`, because its store links are real symlinks, which may need
administrator rights or Developer Mode. Things to know:
converts back the same way. CI always uses the normal layout. On Windows, pnpm links with
junctions when you lack the symlink privilege, so no administrator rights or Developer Mode are
needed. Things to know:
- Keep `~/node_modules` (and any other `node_modules` above the store) out of your home
directory. Node resolves upward from the store slot, so a stray one there supplies
@@ -51,7 +51,7 @@ administrator rights or Developer Mode. Things to know:
- Native addons are never rebuilt in place in a shared slot: each CPU gets its own build
beside it (see [`native-build-entry.cjs`](../config/scripts/native-build-entry.cjs)), so
cross-arch packaging is safe for other worktrees.
- `ORCA_PNPM_GLOBAL_VIRTUAL_STORE=1` opts in on Windows and `=0` opts out anywhere. Keep it set
- `ORCA_PNPM_GLOBAL_VIRTUAL_STORE=0` opts out. Keep it set
in your shell: `pnpm run` re-checks the install and relinks a worktree whose layout no longer
matches.
+4 -8
View File
@@ -15,18 +15,14 @@ function isCi(env) {
*
* Off under CI, which packages from, caches, and verifies a project-local node_modules, unless
* `ORCA_PNPM_FORCE_GLOBAL_VIRTUAL_STORE_IN_CI=1` (the dependency-isolation job).
* Windows needs `ORCA_PNPM_GLOBAL_VIRTUAL_STORE=1` because its store links are true symlinks,
* unverified for users without admin or Developer Mode; `=0` opts out anywhere else.
* On everywhere else, including Windows: without the symlink privilege pnpm links with
* junctions, which standard users can create. `ORCA_PNPM_GLOBAL_VIRTUAL_STORE=0` opts out.
*/
function usesGlobalVirtualStore({ env = process.env, platform = process.platform } = {}) {
function usesGlobalVirtualStore({ env = process.env } = {}) {
if (isCi(env)) {
return env[FORCE_IN_CI_ENV] === '1'
}
const choice = env[GLOBAL_VIRTUAL_STORE_ENV]
if (choice === '0' || choice === '1') {
return choice === '1'
}
return platform !== 'win32'
return env[GLOBAL_VIRTUAL_STORE_ENV] !== '0'
}
module.exports = {
@@ -11,26 +11,23 @@ const {
describe('usesGlobalVirtualStore', () => {
const cases = [
// [env, platform, expected]
[{}, 'darwin', true],
[{}, 'linux', true],
[{}, 'win32', false],
[{ [STORE_ENV]: '1' }, 'win32', true],
[{ [STORE_ENV]: '0' }, 'win32', false],
[{ [STORE_ENV]: '0' }, 'darwin', false],
[{ [STORE_ENV]: 'yes' }, 'linux', true],
[{ CI: 'true' }, 'darwin', false],
[{ CI: '1' }, 'linux', false],
[{ GITHUB_ACTIONS: 'true' }, 'linux', false],
[{ CI: 'true', [STORE_ENV]: '1' }, 'win32', false],
[{ CI: 'true', [FORCE_IN_CI_ENV]: '1' }, 'linux', true],
[{ GITHUB_ACTIONS: 'true', [FORCE_IN_CI_ENV]: '1' }, 'win32', true],
[{ [FORCE_IN_CI_ENV]: '1', [STORE_ENV]: '0' }, 'darwin', false],
[{ CI: 'false' }, 'darwin', true],
[{ CI: '0' }, 'linux', true]
// [env, expected]; platform-independent, so Windows standard users get it too.
[{}, true],
[{ [STORE_ENV]: '1' }, true],
[{ [STORE_ENV]: '0' }, false],
[{ [STORE_ENV]: 'yes' }, true],
[{ CI: 'true' }, false],
[{ CI: '1' }, false],
[{ GITHUB_ACTIONS: 'true' }, false],
[{ CI: 'true', [STORE_ENV]: '1' }, false],
[{ CI: 'true', [FORCE_IN_CI_ENV]: '1' }, true],
[{ GITHUB_ACTIONS: 'true', [FORCE_IN_CI_ENV]: '1' }, true],
[{ [FORCE_IN_CI_ENV]: '1', [STORE_ENV]: '0' }, false],
[{ CI: 'false' }, true],
[{ CI: '0' }, true]
]
it.each(cases)('env %j on %s -> %s', (env, platform, expected) => {
expect(usesGlobalVirtualStore({ env, platform })).toBe(expected)
it.each(cases)('env %j -> %s', (env, expected) => {
expect(usesGlobalVirtualStore({ env })).toBe(expected)
})
})
+1 -1
View File
@@ -169,7 +169,7 @@ overrides:
packageExtensionsChecksum: sha256-TrarseUCmMKP0lVjkfyLP2TAvkGZMZzvzPxjKY48nrY=
pnpmfileChecksum: sha256-568iOYVj6ZdABzEY52uLAgKwLTmlyqdEBiaV2dJCY74=
pnpmfileChecksum: sha256-6l6qdgUHKyTLYIQLx/UGfGRnEiFXxIaSlGMgK4mttEw=
patchedDependencies:
'@vscode/windows-process-tree@0.8.0': a09f2e8b2b4e73ef20c317af91f9e06c09abf62fa2c891d99b16f53047f596fd