-
-
Notifications
You must be signed in to change notification settings - Fork 217
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
Improved shell
option
#985
Comments
Is it really worth spending a lot of effort on this? Almost every use-cases is better done with We are also not doing users any favors by making I also fear this will create a large maintenance burden and also result in us having to deal with security issues.
I would not know what shell the user has installed, which would limit this to just local scripts. And even then, it would mean users cannot easily share their scripts with others or maybe even other devices they own. |
Alright, sounds good. 👍 I'm working on improving the documentation right now. I'll include more information about avoiding shells, and how the Side note: we do agree that shells should almost never be used programmatically, which I strongly believe in too! :) In the end, many features provided by Execa are actually similar to features provided by shells: command execution, I/O redirection, piping, background process, signal termination, exit code, etc. But it's done in a programmatic-friendly way, as opposed to using a terminal-entry-like DSL. |
I'm in full agreement. |
I was reading the original (very long) issue and the original intent behind The issue is that The ideal situation seems to be to run I wanted to bring that up, but this does not change this issue's status. |
Maybe worth mention in https://github.com/sindresorhus/execa/blob/main/docs/shell.md ? That pretty much the only reason to use |
Good point. Added #997 to follow up on this. |
Problems
The
shell
option currently has several shortcomings making it both unsecure and not cross-platform.(For reference, link to the code in Node.js)
shell: true
does not make senseshell: true
runs/bin/sh -c ...
on Unix andcmd.exe /d /s /c "..."
on Windows.This means the shell command must work on both Unix shells and
cmd.exe
. In practice, most ofcmd.exe
syntax does not work with Unix shells, with very few exceptions (such as&&
).So
shell: true
is actually used in one of two ways, and neither makes sense:shell: true
does on Windows: it runscmd.exe
instead.There are potentially some edge cases where this might be useful. For example, npm allows installing different binaries for Unix and Windows, by using different file extensions like
*.cmd
. Those cross-OS binaries would be designed to run withshell: true
, running OS-specific shell code. However, I believe this is not common. Notable examples include Yarn.shell
does not escape argumentsWhen using the following:
Execa actually interprets this as calling
file one two three
. While the user clearly indicates that the first space should be escaped, it is not. Not only if this against user's intent, it is also a security risk.The reason is that
child_process.spawn()
lets users handle their own quoting, when using theshell
option. It just concatenates arguments with spaces as delimiters. That's probably because quoting is finicky. Also, theshell
option allows any file path to be passed (as opposed to an enum of allowed shells), so it's a little harder forchild_process.spawn()
to know which shell is being used.shell
can merge argumentsIn a similar way, when the
shell
option is used, some arguments might be merged together. For example:Is interpreted as
file "one two"
, i.e. as a single argument instead of two.Binary lookup
That's a more minor issue, but
shell: true
uses absolute file path/bin/sh
(and/system/bin/sh
on Android). It probably should usesh
and let the OS does aPATH
lookup instead. This would be more cross-platform.Solutions
Automatic quoting
We could allow specific shells as possible values for the
shell
option. Likesh
,bash
,zsh
,dash
,tcsh
,ksh
,fish
,cmd.exe
,powershell
. For example:Is interpreted as
file '"one' 'two"'
, i.e. two arguments.All Unix shells might be able to use the same quoting logic (single quotes), so I don't think the quoting logic would be too hard to implement and maintain. Actually, we already use the following logic for
result.escapedCommand
. We would need to tweak and thoroughly test it due to the security implication, but that's doable.execa/lib/arguments/escape.js
Lines 62 to 72 in fdd8a9f
Discourage
shell: true
We could rename
shell: true
toshell: 'unknown'
, to discourage it.We would rename
shell: false
toshell: 'none'
, the default value.Backward compatibility
The above would be mostly backward compatible:
shell: 'bash'
. Even if they were, the above would just probably quote their arguments, which would only be breaking if they rely on arguments being concatenated.shell: boolean
in the source code and type. Its behavior would not change. But we would undocument it and deprecate it.End result
This would result in the following
shell
option:'none' | 'sh' | 'bash' | ... | 'cmd.exe' | 'unknown'
. By default, there is no shell. If users wants to use a shell, they must pick one. They can still pick'unknown'
, but our documentation warns against it.All options but
'unknown'
would be more cross platform, and more secure.What do you think?
The text was updated successfully, but these errors were encountered: