helperPath replace produces 'app.asar.unpacked.unpacked/…' when caller is itself in app.asar.unpacked → posix_spawnp ENOENT

Open Beginner friendly
#923 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
76/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
electron, node.js, typescript

Research direction

Start in src/unixTerminal.ts at the helperPath replacements and reproduce the reported path transformation with a caller already under app.asar.unpacked. Ensure an already-unpacked helper path is not rewritten again, then verify the resulting spawn-helper path exists and launches in the described Electron or Node.js setup.

Written by the indexing model from the issue text.

Description

Summary

src/unixTerminal.ts#L19-L20 resolves helperPath, then runs:

helperPath = helperPath.replace('app.asar', 'app.asar.unpacked');
helperPath = helperPath.replace('node_modules.asar', 'node_modules.asar.unpacked');

String.prototype.replace with a string argument replaces the first occurrence. When the resolved helperPath already contains app.asar.unpacked/… (because the caller of node-pty lives inside app.asar.unpacked too, not inside app.asar), the substring app.asar matches the prefix of app.asar.unpacked and the replace produces a path like …/app.asar.unpacked.unpacked/node_modules/node-pty/build/Release/spawn-helper, which doesn't exist on disk.

posix_spawn then fails with ENOENT and node-pty throws the generic posix_spawnp failed., which is widely misdiagnosed as a code-signing / hardened-runtime / sandbox problem.

Reproduction
// simulate what unixTerminal.js does when the caller is itself unpacked
let helperPath = '/path/to/MyApp.app/Contents/Resources/app.asar.unpacked/node_modules/node-pty/build/Release/spawn-helper';
helperPath = helperPath.replace('app.asar', 'app.asar.unpacked');
console.log(helperPath);
// → /path/to/MyApp.app/Contents/Resources/app.asar.unpacked.unpacked/node_modules/node-pty/build/Release/spawn-helper
//                                                            ^^^^^^^^^^^^^^^^^^^ bogus

This affects packaged Electron apps that:

  1. Run node-pty from a separate child process spawned with ELECTRON_RUN_AS_NODE=1 (which strips Electron's asar shim and uses plain Node module resolution), AND
  2. Have that child binary itself living in app.asar.unpacked.

In that combination __dirname resolves to the real app.asar.unpacked/… filesystem path rather than the asar-shimmed app.asar/… path, so the replace runs against a string that already contains app.asar.unpacked. VS Code, Theia, etc. don't hit this because they call node-pty from the Electron main/renderer process where the asar shim is in play and __dirname reports app.asar/….

Suggested fix

Guard each replace so it doesn't fire when the unpacked path is already present:

if (helperPath.indexOf('app.asar.unpacked') === -1) {
  helperPath = helperPath.replace('app.asar', 'app.asar.unpacked');
}
if (helperPath.indexOf('node_modules.asar.unpacked') === -1) {
  helperPath = helperPath.replace('node_modules.asar', 'node_modules.asar.unpacked');
}

Or anchor the replace with a path-separator regex, e.g. .replace(/app\.asar([\\/])/, 'app.asar.unpacked$1').

Bonus: misleading error

src/unix/pty.cc#L373 reports posix_spawnp failed. without the underlying errno. Surfacing strerror(err) (this case would say No such file or directory) would have made this trivially diagnosable instead of sending people down the code-signing rabbit hole. Happy to send a separate PR for that.

Environment
  • node-pty 1.1.0
  • macOS arm64, Electron 32 (also reproduces with system Node ≥18 when require'ing node-pty from a path inside app.asar.unpacked)
Dominant language
TypeScript
Stars
2k
Forks
337
Avg merge
21h 58m
Merged PRs (30d)
3

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from microsoft/node-pty

All issues in microsoft/node-pty

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.