-
Notifications
You must be signed in to change notification settings - Fork 230
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
Improve PowerShell command and argument escaping #1611
Conversation
Really appreciating the tests 🥳 |
I'm gonna rewrite this to be less aggressive on the argument escaping. For instance, if someone has a launch.json that is "","arg1","arg2", we should allow expressions to be used. e.g. I think very minimal escaping should be done for these parameters, it doesn't provide any defense really because I can just code inject into the "command" .ps1 script |
…string Fixes #1608 Apply suggested Rosyln Fix
@andschwa the first parameter in the launch config is now always quoted, which will work for both path and command arguments. It passes all tests and all vscode extension tests currently (I removed the pathing escape tests which are no longer relevant). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lookin' good :) couple of questions and suggestions
{ | ||
sb.Append(arg); | ||
} | ||
sb |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: consider,
sb.Append(' ').Append(ArgumentEscaping.Escape(arg));
Personally I like using text
as the variable for a string builder to enable this:
text.Append(' ')
.Append(ArgumentEscaping.Escape(arg));
Very minor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was matching style of other things in PSES, we can certainly do this if @andschwa doesn't mind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally fine. I'm not super aggressive about style, I think anytime a style question is in play it should be addressed by tooling rather than back and forth on PRs. Do what you think is readable 😄
case '`': | ||
sb.Append('`').Append(curr); | ||
break; | ||
var wildcardEscapedPath = WildcardPattern.Escape(path); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May need to manually handle ` still due to PowerShell/PowerShell#16306. There is a good chance that this seemingly over engineered logic was here due to issue with that API. Unsure when it was added though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably do need to escape it to handle a situation where it exists in a file name at least at the command level, will probably leave it alone at an argument level
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#123 is the relevant reasoning, I don't think we need to escape every path that comes in, this should be more handled on the output side if required as part of a cmdlet argument, if it's thought the cmdlet will interpret handling characters, because in some cases that may be exactly what the caller wants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try to add a test for SetLineBreakpoint which is the only other place this is referenced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably do need to escape it to handle a situation where it exists in a file name at least at the command level, will probably leave it alone at an argument level
Yeah it gets tricky with no real way to please everyone here. On one hand you want to enable VSCode variables like ${workspaceFolder}
in which case you can't really escape manually, and on the other hand some folks may want to use expressions.
Like you said though for the command path always escape is a clear winner for sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SeeminglyScience the compromise for my implementation is that:
- Command is always wrapped in double quotes because it is used by the call operator, so
${} expressions will still work if you want to pass a file and not a command, the only file that won't work in this case is if the filename contains $ (), I think that's reasonable enough to just say "dont name your files this way", should probably have an explicit exception check for this. - Argument is only wrapped in quotes if you specify a space. If you really need to be literal or use workspacefolder in an arg and have it be safe, you should wrap it in quotes, a scriptblock, or $(). I think that's a good compromise
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SeeminglyScience looks like all the debugserver tests were commented out by @rjmholt after his commit and probably need to be rewritten. @andschwa can you come up with a way to get a debugservice instantiated to a point I can run tests against it? Been trying to figure it out and it's too much for my non-C# brain at the moment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah it gets tricky with no real way to please everyone here. On one hand you want to enable VSCode variables like ${workspaceFolder} in which case you can't really escape manually, and on the other hand some folks may want to use expressions.
Wouldn't this be interpolated before it gets to the LSP server? I could be wrong, I just assumed that the Code client would interpolate their own variable expressions, and then send the full string over.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like all the debugserver tests were commented out
I will prioritize this. I really want them up. Thanks for working on this issue!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah it gets tricky with no real way to please everyone here. On one hand you want to enable VSCode variables like ${workspaceFolder} in which case you can't really escape manually, and on the other hand some folks may want to use expressions.
Wouldn't this be interpolated before it gets to the LSP server? I could be wrong, I just assumed that the Code client would interpolate their own variable expressions, and then send the full string over.
They do, the problem is that you don't know that they are a path or an interpolation once they arrive to the LSP. I think this implemention is a good compromise.
src/PowerShellEditorServices/Services/DebugAdapter/Handlers/ConfigurationDoneHandler.cs
Show resolved
Hide resolved
I built a .vsix of this and it is working for pester test extension, native pester codelens, and all my debug launch.json configurations for the last day or so without issue. It is good as is unless we want to adjust for @SeeminglyScience's nit, and cover the debugservice tests in a separate PR since looks like they all need to be redone anyways. |
💯 Can merge! |
public static string Escape(string Arg) | ||
{ | ||
// if argument is a scriptblock return as-is | ||
if (Arg.StartsWith("{") && Arg.EndsWith("}")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JustinGrote Should we strip whitespace first? In case it's { ... }
or some other variation with (pointless) spaces before/after.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JustinGrote Should we strip whitespace first? In case it's
{ ... }
or some other variation with (pointless) spaces before/after.
I think this is another case of "overly helpful", if you specified your debug config and left a space at the beginning or the end before your scriptblock, I have to think you may have had an intention there.
Coming back to to this @JustinGrote and deciding we need to not quote escape args with spaces in them. |
Fixes #1608
@rjmholt please ensure that changing '' to backtick-quote is what was intended, it looked like a bug to me that was causing the triple-quotes.
@SeeminglyScience @andschwa Per my last PR, maybe we are being "overly helpful" with the escaping of the arguments and should instead throw errors to encourage editors to fix their problems at the source?
For instance in a launch.json, specifying a parameter like this is a clear mistake, but this tool will accept it, escape it, and maybe produce a difficult-to-troubleshoot result:
args: "-Path","I'putaquoteinthewrongplaceaccidentally"