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

feat: write script and args to temp file and run that #78

Merged
merged 3 commits into from
Jun 21, 2022
Merged

Conversation

nlf
Copy link
Contributor

@nlf nlf commented Jun 15, 2022

  1. we now properly escape strings for shells instead of using the horribly incorrect JSON.stringify() approach
  2. rather than trying to build a string to pass to the shell that needs to be (in windows) double escaped, we can instead write the script and the singly escaped arguments to a file and run that file

i've done my best in spelunking through open issues and verifying this approach fixes our reported issues, though it's very likely there are more than these:

closes #31
closes #60
closes npm/cli#3067
closes npm/cli#3337
closes npm/cli#3600
closes npm/cli#3680
closes npm/cli#4873
closes npm/cli#4968
closes npm/cli#5004

lib/escape.js Fixed Show fixed Hide fixed
@nlf nlf force-pushed the nlf/file-first branch 2 times, most recently from 10ae363 to d678908 Compare June 15, 2022 17:49
@nlf nlf force-pushed the nlf/file-first branch from d678908 to f3561c3 Compare June 15, 2022 18:54
@nlf nlf marked this pull request as ready for review June 15, 2022 18:55
@nlf nlf requested a review from a team as a code owner June 15, 2022 18:55
return `''`
}

if (!/[\t\n\r "#$&'()*;<>?\\`|~]/.test(input)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wanna be sure it's intentional that we're only looking for certain whitespace characters, and not using \s. Will approve assuming this is intentional.

Copy link
Contributor Author

@nlf nlf Jun 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it was meant to be a list of each individual character that causes us to need single quotes to avoid expansion/keep the argument in one piece, the switch could likely be made but i felt like this was more explicit and clear

@nlf nlf merged commit 0a351e9 into main Jun 21, 2022
@nlf nlf deleted the nlf/file-first branch June 21, 2022 18:38
@rhendric
Copy link

Did you test this with scripts that call executables from dependency packages? As we've discussed in the past, scripts that call executables like node require a different amount of argument escaping from scripts that call batch-file wrappers like what npm creates (used to create?) for, e.g., rimraf. I suspect putting the arguments into another batch file doesn't change this requirement, but I can't test that right this moment and I'm wondering if you did.

I still stand ready to assist with doing this the right way. The first step is still merging npm/exec#15, unless your plans have changed.

@nlf
Copy link
Contributor Author

nlf commented Jun 21, 2022

Did you test this with scripts that call executables from dependency packages?

> npx node@16 -e 'console.log("hello^&")'
hello&

> npx cowsay "hello^&"
 _________
< hello& >
 ---------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

seems to be working right?

@rhendric
Copy link

Literal carets are the problem character here, and the problems sometimes don't show up until you try lots of them. Try npx cowsay "hello^^^^^^" and see if you get the same results as cowsay "hello^^^^^^" after installing cowsay. I know of trickier edge cases involving pipes and more advanced shell syntax, but if you pass that test I expect most users would consider the result good enough.

@nlf
Copy link
Contributor Author

nlf commented Jun 21, 2022

oh interesting..

> npx cowsay "hello^^^^^^"
 __________
< hello^^^ >
 ----------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

> cowsay "hello^^^^^^"
 _____________
< hello^^^^^^ >
 -------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

so you're right, we do still have the problem with shim scripts. thank you for the reminder!

the solution is to double up the escaping if the first thing we're calling is a batch file, right? i think it's likely we're not going to go down the road of re-escaping the script as defined in the package.json, but we can certainly grab the initial command and use that to trigger double escaping if we need to

@rhendric
Copy link

That'd be an improvement over this patch (which is already an improvement over the status quo), and quite possibly ‘good enough’. It is possible to write scripts for which this would do the wrong thing: consider "rimraf build & rimraf tmp & node regenerate.js"; the relevant command is node, which is not a batch file, and double escaping would be incorrect because rimraf is one. Another example: "node print-data.js | node this-script-accepts-args.js"; neither command in this pipeline is a batch file but any arguments to the second one need double escaping because of the pipe (and if that command were a batch file, they would need quadruple escaping!).

If you want to enable correct escaping for scripts like the above, a true solution requires parsing the syntax of the script, not to add escape characters to it necessarily, but to determine the level of escaping that terminal arguments would need. If you think examples like the above are acceptably rare, then what you proposed is a reasonable shortcut.

@nlf
Copy link
Contributor Author

nlf commented Jun 21, 2022

If you think examples like the above are acceptably rare, then what you proposed is a reasonable shortcut

I think this is likely to be the case. We certainly get few enough complaints about extremely complicated scripts for me to not feel like this further parsing is necessary. At least not right now.

I'll have a pull request up that double escapes if the first command in the script resolves to a .cmd file in a few minutes

@nlf
Copy link
Contributor Author

nlf commented Jun 21, 2022

i pushed #80 which i think gets us "close enough" for now at least. let me know your thoughts, if you have a moment to review. i really appreciate your continued eyes on this problem. i think if this series of changes isn't good enough, then we'll be circling back to adopting and modifying puka, but i'm really hopeful this is enough for the 99%

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment