Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spago fails to build on Windows and Node v 21.7 #1219

Open
ntwilson opened this issue Apr 22, 2024 · 19 comments
Open

Spago fails to build on Windows and Node v 21.7 #1219

ntwilson opened this issue Apr 22, 2024 · 19 comments

Comments

@ntwilson
Copy link
Contributor

On linux everything works fine, but on my Windows machine, spago fails to build on Node 21.7 with

node:internal/child_process:421
    throw new ErrnoException(err, 'spawn');
    ^

Error: spawn EINVAL
    at ChildProcess.spawn (node:internal/child_process:421:11)
    at Object.spawn (node:child_process:761:9)
    at C:\Git\WebPlatform\node_modules\purescript-psa\output\Node.ChildProcess\foreign.js:16:49
    at __do (C:\Git\WebPlatform\node_modules\purescript-psa\output\Main\index.js:545:27)
    at ChildProcess.<anonymous> (C:\Git\WebPlatform\node_modules\purescript-psa\output\Node.ChildProcess\foreign.js:125:24)
    at ChildProcess.emit (node:events:519:28)
    at ChildProcess._handle.onexit (node:internal/child_process:292:12)
    at onErrorNT (node:internal/child_process:484:16)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  errno: -4071,
  code: 'EINVAL',
  syscall: 'spawn'
}

Node.js v21.7.3
[error] Failed to build.

It works just fine on 21.6:
image

I'm not convinced the error is in spago itself, but in Node.js 21.7 I am able to do npx purs --version just fine (my machine is on purs version 0.15.15 and spago version 0.21.0)

@f-f
Copy link
Member

f-f commented Apr 22, 2024

The 0.21.x line is the legacy codebase, which is not maintained anymore. Would you be able to give this a try with spago@next?

@ntwilson
Copy link
Contributor Author

spago@next seems to work with both versions of node (on a fresh project from spago init) 🎉. Is there anything to be concerned with if we switch to spago@next for production use? I notice it says it's still in alpha.

@f-f
Copy link
Member

f-f commented Apr 24, 2024

Good to know that the new spago works!

It's not alpha in the sense that "things are changing all the time" anymore, but more like "it still has paper cuts that we should fix before calling it ready for general usage"

We are using it in production at work, but YMMV. And if you do use it, please report weird things as soon as possible so we can get them fixed 🙂

@f-f
Copy link
Member

f-f commented Apr 24, 2024

That said, I'll close this ticket as it doesn't affect the new spago (which is now living in this repo)

@f-f f-f closed this as completed Apr 24, 2024
@hank-der-hafenarbeiter
Copy link

I ran into this problem as well on Windows 10 and it seems to affect the new version of spago. I'm using spago 0.93.39 and Node.js v20.17.0. Spawn

The problematic call is this one

// spago/bin/bundle.js:85269
var spawn$prime = function() {
  return function(command2) {
    return function(args) {
      return function(opts) {
        return function() {
          return spawn2(command2, args, opts);
        };
      };
    };
  };
};

It's probably connected to this

@AZMCode
Copy link

AZMCode commented Oct 10, 2024

Can confirm this also happens on spago 0.93.40

@f-f f-f reopened this Oct 10, 2024
@f-f
Copy link
Member

f-f commented Oct 10, 2024

I'll reopen this since it seems to be a recurring issue - we should try to find a way to replicate this in CI so we can issue a reasonable fix.

@AZMCode
Copy link

AZMCode commented Oct 11, 2024

Is there any workaround we could do other than downgrade the system nodejs? Anywhere we could pass a --security-reverts flag when invoking spago? I looked around but couldn't find any.

@f-f
Copy link
Member

f-f commented Oct 12, 2024

We are using Node 22 in CI:

- name: Setup node and npm
uses: actions/setup-node@v4
with:
node-version: 22

So I wonder if there's something else at play here?

@AZMCode
Copy link

AZMCode commented Oct 12, 2024

I can confirm I am running Node v22.9.0, and have this issue, so maybe that isn't it.

@AZMCode
Copy link

AZMCode commented Oct 12, 2024

I don't think the issue has been brought up here, but maybe this has to do with the args passed to the spawn command?

https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2

Could be related, and has caused similar issues for other projects in windows since the patch rolled out in all release lines, including purescript-lsp-server on my machine, which recently got fixed.

@AZMCode
Copy link

AZMCode commented Oct 12, 2024

Here's the command, arguments to the command, and other options (including full environment variables and stack trace) of the spawn call that is causing the crash I'm experiencing. It appears in some installations, like mine (I'm using git bash and chocolatey on windows if it's any use), the purs compiler itself can be a .cmd file, meaning the shell option has to be used when calling it, otherwise an EINVAL error will happen. It appears spago is calling the purs compiler without this option, causing an immediate crash.

https://gist.github.com/AZMCode/616ac8a95ee5e1a93d4a92ce573d5658

Edit: Actually maybe this has to do with the path conversion Git Bash performs. I'll test that when I get the chance

@AZMCode
Copy link

AZMCode commented Oct 12, 2024

Can confirm the bug doesn't happen outside of Git Bash

Should I open a new bug report?

Edit: Turns out I did test it with spago@next. This happens even when running outside of git bash

@AZMCode
Copy link

AZMCode commented Oct 12, 2024

The issue starts right here
https://github.com/purescript/spago/blob/b13857dcae4c908af20f5ad010b2581f6a4bab75/src/Spago/Cmd.purs#L182C1-L183C44

The desicion is taken to report a .cmd command path, but no information about whether, correspondingly, the shell flag should be used is reported to the exec command this return value is later used in.

Note that enabling the shell flag will inevitably introduce shell-interpretation bugs into the package manager. If the path for the filename or arguments is somehow malicious, arbitrary code could be executed. However, there is no choice but to do this if you're trying to run a '.cmd' in windows, as per the nodejs security release comments.

By the looks of what you're trying to execute, however, (Literally just 'purs.cmd' and the like) this shouldn't be an issue and the spawn flag could be enabled

@AZMCode
Copy link

AZMCode commented Oct 12, 2024

The askVersion action in the same function makes the same mistake, which is what is crashing the package manager

@AZMCode
Copy link

AZMCode commented Oct 12, 2024

In all honesty, I've given fixing it a good whirl, and I'm out of my depth here. I sure hope this error is eventually worked out so I can actually use purescript on my PC.

I think the spawn issue is what I've highlighted here so far, but this secondary issue I've encountered with futime while trying to fix the first one is keeping me from making any progress. Whenever the first issue is fixed, I'll report with a new issue regarding the second one if I still have it.

@cakekindel
Copy link
Contributor

Ran into this trying to repro the CI failures on #1285. It's definitely caused by trying to invoke spawn on .cmd files, although I can't seem to directly prevent it with node's --security-revert flag so I'm not 100% sure when node "fixed" this behavior.

A proper fix would probably be doing some additional windows checks in Spago.Cmd;

  1. is host OS windows?
  2. does command we're about to run end in .cmd?
  3. (y) instead of spawn(cmd, args) do spawn('cmd', [cmd, ...args]) (or something like this)

This was on a fresh Windows 10 virtualbox image.

version things
Windows 10 Home 22H2
node 22.11.0
npm 10.9.0
purs 0.15.15
  tried .cmd via `npm i -g purescript@latest`
  and .exe via `npx purs-installer install --purs-version 0.15.15`
[email protected]
Hacky workaround if this is totally blocking your use of spago

I was able to temporarily bypass this by editing %APPDATA%\Roaming\npm\node_modules\spago\bin\bundle.js. Find a function spawnXXX (XXX are digits) that has "Failed pattern match at Spago.Cmd, and edit the options object passed to execa like so:

          return bind37(execa(cmd)(args)(function(v) {
            return {
              cleanup: v.cleanup,
              preferLocal: v.preferLocal,
              stripFinalNewline: v.stripFinalNewline,
              extendEnv: v.extendEnv,
              env: v.env,
              encoding: v.encoding,
              argv0: v.argv0,
              ipc: v.ipc,
              stdioExtra: v.stdioExtra,
              detached: v.detached,
              uid: v.uid,
              gid: v.gid,
              timeout: v.timeout,
              maxBuffer: v.maxBuffer,
              windowsVerbatimArguments: v.windowsVerbatimArguments,
              windowsHide: v.windowsHide,
              windowsEnableCmdEcho: v.windowsEnableCmdEcho,
              cwd: opts.cwd,
+             shell: new Just(true),
              stdin: stdinOpt,
              stdout: new Just(pipe2),
              stderr: new Just(pipe2)
            };
          }))(function(subprocess) {

This unblocks being able to run spago build, but I think it breaks some other spawny things like bundle.

@cakekindel
Copy link
Contributor

@AZMCode

@AZMCode
Copy link

AZMCode commented Nov 2, 2024

Thanks for the effort, but applying a similar fix (I did it at the execa bindings level), I stumbled upon another bug. I could definitely give it a shot, but I'd have to bootstrap the compiler and it's a bit of a headache.

I've just ended up using codespaces due to other personal reasons, so this problem is not as bad for me now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants