pkg icon indicating copy to clipboard operation
pkg copied to clipboard

Patched `childProcess.spawn` (and alikes) fail on executing `node -e 'code'`

Open medikoo opened this issue 3 years ago • 9 comments

What version of pkg are you using?

5.6.0

What version of Node.js are you using?

14.9.0

What operating system are you using?

macOS

What CPU architecture are you using?

x86_64

What Node versions, OSs and CPU architectures are you building for?

node16-linux-x64

Describe the Bug

Running package with following code

childProcess.spawn("node", ["-e", "console.log('foo')"], { stdio: "inherit" });

Results with unexpected error:

./dist/index-macos 
node:internal/modules/cjs/loader:936
  throw err;
  ^

Error: Cannot find module '/Users/medikoo/Projects/_tests/repro-pkg-bug/-e'
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
    at Function._resolveFilename (pkg/prelude/bootstrap.js:1912:46)
    at Function.Module._load (node:internal/modules/cjs/loader:778:27)
    at Function.runMain (pkg/prelude/bootstrap.js:1940:12)
    at node:internal/main/run_main_module:17:47 {
  code: 'MODULE_NOT_FOUND',
  requireStack: []
}

I believe it's due to patching args at https://github.com/vercel/pkg/blob/5.6.0/prelude/bootstrap.js#L2033 And it appears -e option is not handled as expected

Expected Behavior

Should print:

foo

To Reproduce

  1. Package following code:
childProcess.spawn("node", ["-e", "console.log('foo')"], { stdio: "inherit" });
  1. Run generated binary

medikoo avatar Apr 27 '22 16:04 medikoo

PR?

robertsLando avatar Apr 28 '22 07:04 robertsLando

@robertsLando As I check, it doesn't seem trivial to fix.

The problem if I see correctly lies here: https://github.com/vercel/pkg/blob/8cd98af1ad7ab74df40fa9ffd5e6decdfb298969/prelude/bootstrap.js#L80-L82 It's not taken into account that node might be run with -e flag to evaluate the code.

In Node.js runtime above check is preceded with the handling of eval arguments: https://github.com/nodejs/node/blob/1a96d83a223ff9f05f7d942fb84440d323f7b596/lib/internal/bootstrap/node.js#L256-L266 Still, this logic seems to rely on functions not accessible outside of Node.js internals, so we can't just copy and paste it in.

What approach would you suggest?

medikoo avatar Apr 28 '22 10:04 medikoo

What approach would you suggest?

The bug is for sure in those lines of code, unfortunally I have no quick solution to propose to you right now, you should make some tests your own. I suggest to create a dedicated unit test for this and run it to test changes you make in bootstrap code until it works

robertsLando avatar Apr 28 '22 11:04 robertsLando

spawn routines of Node.js appear to interpret node as the executable itself.

In our case, it would make sense to remove that, and treat node the same way as any other executables in PATH.

This is not necessarily what you want, though. What are you trying to do here? Do you want a pkg-generated executable to function as Node.js runtime?


A simple test with notnode:

sudo ln -sf /usr/bin/node /usr/bin/notnode

then,

childProcess.spawn("notnode", ["-e", "console.log('foo')"], { stdio: "inherit" });

prints foo.

jesec avatar May 01 '22 22:05 jesec

This is not necessarily what you want, though. What are you trying to do here? Do you want a pkg-generated executable to function as Node.js runtime?

We bundle Serverless Framework and it has command to install plugins which under the hood runs npm (which is bundled together with a Framework), and in some plugin install scenarios npm install crashes when running postinstall scripts as https://github.com/medikoo/es5-ext/blob/v0.10.59/package.json#L115

medikoo avatar May 02 '22 08:05 medikoo

This is not necessarily what you want, though. What are you trying to do here? Do you want a pkg-generated executable to function as Node.js runtime?

We bundle Serverless Framework and it has command to install plugins which under the hood runs npm (which is bundled together with a Framework), and in some plugin install scenarios npm install crashes when running postinstall scripts as https://github.com/medikoo/es5-ext/blob/v0.10.59/package.json#L115

🤔 Do you want the pkg-generated executable to evaluate that statement (that is, to function as the Node.js runtime)? Or it can be assumed that there is a node in PATH?

In the first case, you can add env: { PKG_EXECPATH: 'PKG_INVOKE_NODEJS' }, to your spawn.

In the second case, I will have to implement the change to make node non-special.

Note that the env variable hack is not officially supported. I am considering to remove the possibility of making a pkg-generated executable to behave as a Node.js runtime in a future major release.


Implementing the node from PATH implies removal of the PKG_EXECPATH, so that would be a major change.

jesec avatar May 02 '22 17:05 jesec

In the first case, you can add env: { PKG_EXECPATH: 'PKG_INVOKE_NODEJS' }, to your spawn.

I was thinking about that, but then it'll crash for users which don't have Node.js normally installed in their system.

It seems the only solid solution is to have node -e .. run with Node.js that's bundled with the executable.

medikoo avatar May 02 '22 19:05 medikoo

I have the exact same problem. My software also wants the user to be able to install plugins, hence, I am bundling npm in the package, but, a few very widely used packages such as core-js-pure have postinstall script in their package.json with the value that looks something like this node -e "try{require('./postinstall')}catch(e){}". As a temporary work-around I have replace npm with yarn, because yarn, unlike npm. doesn't undo the installation when postinstall fails. There are other work around options available with yarn such as using dependenciesMeta in package.json or enableScripts in .yarnrc.yml.

Even with these work arounds, I am worried that this problem might break something in the future while developing some plugins etc. Upon reading this discussion, I think the work needed to resolve this issue lies in adding some logic to parse -e here as mentioned by @medikoo

https://github.com/vercel/pkg/blob/8cd98af1ad7ab74df40fa9ffd5e6decdfb298969/prelude/bootstrap.js#L80-L82

Maybe an additional change might be required here to load the module correctly.

https://github.com/vercel/pkg/blob/8cd98af1ad7ab74df40fa9ffd5e6decdfb298969/prelude/bootstrap.js#L1938-L1941

cruxcode avatar Jul 30 '22 15:07 cruxcode

I have done some changes to my fork to show how the solution will look approximately. I have done a single commit, hence, it won't be difficult to compare changes.

To test the changes, change directory into examples/spawn-eval and run yarn run pkgExe && yarn run test. I have only applied one check and that is if /snapshot directory exists in the spawned process.

If these changes are in the right direction, I will put in some more time to make it perfect.

cruxcode avatar Jul 30 '22 16:07 cruxcode

This issue is stale because it has been open 90 days with no activity. Remove the stale label or comment or this will be closed in 5 days. To ignore this issue entirely you can add the no-stale label

github-actions[bot] avatar Oct 29 '22 00:10 github-actions[bot]

bump

medikoo avatar Oct 29 '22 07:10 medikoo

We are also experiencing troubles with this issue.

kubevious avatar Nov 11 '22 22:11 kubevious

Any update on this? 😭

jcs090218 avatar Jan 09 '23 14:01 jcs090218

This issue is stale because it has been open 90 days with no activity. Remove the stale label or comment or this will be closed in 5 days. To ignore this issue entirely you can add the no-stale label

github-actions[bot] avatar Apr 10 '23 00:04 github-actions[bot]

bump

medikoo avatar Apr 12 '23 12:04 medikoo

This issue is stale because it has been open 90 days with no activity. Remove the stale label or comment or this will be closed in 5 days. To ignore this issue entirely you can add the no-stale label

github-actions[bot] avatar Jul 12 '23 00:07 github-actions[bot]

bump

jcs090218 avatar Jul 12 '23 05:07 jcs090218

This issue is stale because it has been open 90 days with no activity. Remove the stale label or comment or this will be closed in 5 days. To ignore this issue entirely you can add the no-stale label

github-actions[bot] avatar Oct 12 '23 00:10 github-actions[bot]

bump

jcs090218 avatar Oct 12 '23 00:10 jcs090218