You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Setting shell=False requires the command to be an list of strings #382
Right now our codemod does not account for the fact that in most cases for shell=False to work the command needs to be a list of strings rather than a single string.
This is a good refinement, so I'm bringing this test case that I thought about to see how we want to handle it.
Say we want to run ls -l | grep '.txt' with subprocess. This has a pipe which is a shell feature. The way you'd write the code for this would be subprocess.run("ls -l | grep '.txt'", shell=True) which would correctly ls any .txt files. If we follow the suggestions in the issue, we would end up converting this to subprocess.run(["ls", "-l", "|", "grep", "'.txt'"], shell=False) which breaks entirely.
There are more complicated ways to handle shell features like a pipe, we could use Popen and subprocess.PIPE, but that deviates from the purpose of this codemod I feel like.
So what do we want to do? Do we want to check if strings like "|" or other shell feature strings are present and not change it?
@clavedeluna that's a really good question. There are definitely valid cases for using shell=True. Maybe the safest heuristic is to simply ignore entirely any cases that have string literals instead of arrays.
subprocess actually does not require a list of strings when run with shell=False, it requires that the first arg be a string |bytes that is a path which exists and resolves to a valid executable.
Args are handled as a list regardless of the arg type.
When shell=True['/usr/bin/sh' , '-c'] is just added to the front of the args list , unless the executable kwarg is set then it over rides args[0]
So to fully solve this issue two things are needed:
The type of the first arg.
The value of the executable kwarg if set to determine if it is a shell. If it is, this is the same as shell=True
If the type can be determined to be a string or bytes, then arg -> shlex.split(arg) could be a simple way to improve the codeMod.
Thanks guys have a great weekend!
In 3.11 this is at line 1800 of subprocess.py
ifisinstance(args, (str, bytes)):
args= [args] # String or bytes arg are allowed when shell=True, string or bytes are then placed in listelifisinstance(args, os.PathLike):
ifshell:
raiseTypeError('path-like args is not allowed when ''shell is true')
args= [args]
else:
args=list(args)
ifshell:
# On Android the default shell is at '/system/bin/sh'.unix_shell= ('/system/bin/sh'ifhasattr(sys, 'getandroidapilevel') else'/bin/sh')
args= [unix_shell, "-c"] +argsifexecutable:
args[0] =executableifexecutableisNone:
executable=args[0]
Activity
clavedeluna commentedon Mar 18, 2024
@drdavella just to be clear since you did not specify the codemod, it's
subprocess-shell-falseyou're talking about, notsandbox-process-creationclavedeluna commentedon Mar 18, 2024
This is a good refinement, so I'm bringing this test case that I thought about to see how we want to handle it.
Say we want to run
ls -l | grep '.txt'with subprocess. This has a pipe which is a shell feature. The way you'd write the code for this would besubprocess.run("ls -l | grep '.txt'", shell=True)which would correctlylsany .txt files. If we follow the suggestions in the issue, we would end up converting this tosubprocess.run(["ls", "-l", "|", "grep", "'.txt'"], shell=False)which breaks entirely.There are more complicated ways to handle shell features like a pipe, we could use Popen and subprocess.PIPE, but that deviates from the purpose of this codemod I feel like.
So what do we want to do? Do we want to check if strings like "|" or other shell feature strings are present and not change it?
drdavella commentedon Mar 19, 2024
@clavedeluna that's a really good question. There are definitely valid cases for using
shell=True. Maybe the safest heuristic is to simply ignore entirely any cases that have string literals instead of arrays.clavedeluna commentedon Mar 19, 2024
Would be a similar logic to #263
So perhaps the most refined heuristic would be to check if:
subprocess.run("echo foo", shell=True), don't do anything1a. similarly, if arg is a var pointing to str literal
don't do anything
LucasFaudman commentedon Apr 20, 2024
subprocess actually does not require a list of strings when run with
shell=False, it requires that the first arg be astring |bytesthat is a path which exists and resolves to a valid executable.Args are handled as a list regardless of the arg type.
When
shell=True['/usr/bin/sh' , '-c']is just added to the front of the args list , unless theexecutablekwarg is set then it over ridesargs[0]So to fully solve this issue two things are needed:
shell=TrueIf the type can be determined to be a string or bytes, then
arg->shlex.split(arg)could be a simple way to improve the codeMod.Thanks guys have a great weekend!
In 3.11 this is at line 1800 of subprocess.py