I'm trying to use a Python's subprocess.Popen to build up a module for Python bindings to a command line interface; pretty much there as far as the CLI-bindings go, but I really want to be able to mask some "private" arguments.
The CLI uses account information, and I want to hide the account credentials from a command prompt title. Below is a screen capture of what appears when I use the login method for my CLI-bindings class.
I know that I'm using plain text for the password here ('TAIL') but I wanted to simply show the usage of what's going on. See from the image that the full command "sent" using the subprocess.Popen is displayed in the prompt's title.
I recently found that there is a way to programmatically change the title using either os or ctypes, so I could effectively mask, or cover-up, the "private" credentials I don't want shown on the command prompt title like shown here:
but is there a better way of disabling "echo-to-title" (for lack of a better name) with subprocess.Popen?
in fact passwords should never be passed as command line arguments to an executable.
Reason:
anybody being able to look at running processes and their parameters can see the password.
One solution is, that the parent process. puts the password in an environment variable and the program to be called fetches the parameter from an environment variable.
so the caller would be something like:
import os
os.environ["ACRTAC_PASSWORD"] = "TAIL"
subprocess.Popen([...])
and the acrtac.py
import os
password = os.environ["ACRTAC_PASSWORD"]
Related
I'm currently doing some work in a server (Ubuntu) without admin rights nor contact with the administrator. When using the help(command) in the python command line I get an error.
Here's an example:
>>> help(someCommand)
/bin/sh: most: command not found
So, this error indicates that most pager is not currently installed. However, the server I'm working on has "more" and "less" pagers installed. So, how can I change the default pager configuration for this python utility?
This one is annoyingly difficult to research, but I think I found it.
The built-in help generates its messages using the standard library pydoc module (the module is also intended to be usable as a standalone script). In that documentation, we find:
When printing output to the console, pydoc attempts to paginate the output for easier reading. If the PAGER environment variable is set, pydoc will use its value as a pagination program.
So, presumably, that's been set to most on your system. Assuming it won't break anything else on your system, just unset or change it. (It still pages without a value set - even on Windows. I assume it has a built-in fallback.)
You can make a custom most script that just invokes less (or even more).
The steps would be:
Set up a script called most, the contents of which are:
#!/bin/sh
less ${#:1} # wierdess is just "all arguments except argument 0"
Put that script in a location that is on your PATH
Then most filename should just run less on that file, and that command should get called from in your python interpreter.
To be honest though, I'd just use Karl's approach.
You can view the various pager options in the source code. That function can be replaced to return whatever is desired. For example:
import pydoc
pydoc.getpager = lambda: lambda text: pydoc.pipepager(text, 'less')
I am simulating an online IDE using docker.
Each time user submits their code, an image will be generated and be run. It is working as expected, however when the code asks for input e.g
print("Begin script")
x = input("Enter your name")
print("you entered")
print(x)
python code to run docker:
container = subprocess.Popen(["docker", "run","-it", "--rm", "--name",imageName,imageName])
I am unable to pass in input to the python script.
It does not even print the prompt "Test input" into terminal
I have tried using docker attach command, and I am enter able to enter into terminal, but it is not sending input to python script
Via comments:
subprocess.run(["docker", "run","-ti", "--rm", "--name",imageName,imageName], capture_output=True)
You're using a function that is described to (emphasis mine)
Run the command described by args. Wait for command to complete, then return a CompletedProcess instance.
You also say
it does not even print the prompt of the input message
This is because you've explicitly told subprocess.run() to capture the output instead of allowing it to be printed to stdout. If you were to print the return value of that call, you'd possibly see the output.
If you just want some static input to be piped to the process and get the output, you could use
proc = subprocess.run(..., input="123\n", capture_output=True)
print(proc.stdout)
to simulate someone entering 123 and a newline.
If you want an interactive experience, you will need to use subprocess.Popen() instead. Wiring the stdin/stdout/stderr pipes is somewhat tricky, especially if you need a TTY-like experience.
I am really sorry that it doesn't answer your question directly, but I am sure it would help.
I think you are trying to make an entire docker container for every user. You don't strictly need that if you only plan to allow them to use your service as a simple IDLE.
You could use something like socat or xinetd to achieve the same.
Here is an example that uses socat to run a python script for anyone who connects to the server: https://gitlab.com/Milkdrop/xmas-2020/-/tree/master/misc/complaint
Also, I recommend AGAINST using exec() or eval() to allow others to execute code on your system. Actually, you should not use them in general either.
I have a jar file that I want to run in the command line and collect it's stdout with a python script.
I make the call as a subprocess like:
def get_output():
process = subprocess.run(['java', '-jar', 'myjar.jar', 'myfileargument'])
But a warning prompt comes up that I am unable to disable, which pauses execution until a user clicks 'OK' or presses enter. Is there a way to essentially 'click ok' in the prompt window that comes up via code and let the python script continue?
If there is no way for you, only using environment variables and parameters to the subprocess, to disable that warning, there is no easy way to do it.
Either you will have to go the road of UI automation, as mentionned by #furas in the comments. It may be relatively easy to do so given the multiple tools/frameworks there is to do that.
Or you may "patch" the jar to not require this warning. If you can replace the annoying .class file by another which will not require to accept the warning, it may be somewhat efficient. Or else you could install a custom ClassLoader in the java program, but it may prove to be difficult.
I am currently in the process of developing a python code that connects to a remote brocade switch using the fabric module and issue some configuration commands. The problem I am facing is when it comes to commands that require an input from the user (i.e. yes/no).
I read several posts that have advised to use Fabric's native settings methods as well as wexpect but none have been successful.
I checked the following links but none were able to help with my code:
how to handle interactive shell in fabric python
How to answer to prompts automatically with python fabric?
Python fabric respond to prompts in output
Below is an example of the command output that requires to be automated:
DS300B_Autobook:admin> cfgsave
You are about to save the Defined zoning configuration. This
action will only save the changes on Defined configuration.
If the update includes changes to one or more traffic isolation
zones, you must issue the 'cfgenable' command for the changes
to take effect.
Do you want to save the Defined zoning configuration only? (yes, y, no, n): [no]
The code that I have written for this is show below (tried to make it exactly the same as the output the command provides):
with settings(prompts={"DS300B_Autobook:admin> cfgsave\n"
"You are about to save the Defined zoning configuration. This\n"
"action will only save the changes on Defined configuration.\n"
"If the update includes changes to one or more traffic isolation\n"
"zones, you must issue the 'cfgenable' command for the changes\n"
"to take effect.\n"
"Do you want to save the Defined zoning configuration only? (yes, y, no, n): [no] " : "yes"}):
c.run('cfgsave')
If there is a way to have it display the output of the command to the screen and prompt me to provide the input that would also be reasonable solution.
I created the simple python script using pexpect, created one spwan process using
CurrentCommand = "ssh " + serverRootUserName + "#" + serverHostName
child = pexpect.spawn(CurrentCommand)
Now I am running some command like ls-a or "find /opt/license/ -name '*.xml'"
using code
child.run(mycommand)
it works fine if running from Pycharm but if running from terminal it is not working it is not able to find any file, I think it is looking into my local system.
Can anyone suggest me something. Thanks
As a suggestion, have a look at the paramiko library (or fabric, which uses it, but has a specific purpose), as this is a python interface to ssh. It might make your code a bit better and more resilient against bugs or attacks.
However, I think the issue comes from your use of run.
This function runs the given command; waits for it to finish; then returns all output as a string. STDERR is included in output. If the full path to the command is not given then the path is searched.
What you should look at is 'expect'. I.e. your spawn with spawn then you should use expect to wait for that to get to an appropiate point (such as connected, terminal ready after motd pushed etc (because ouy might have to put a username and password in etc).
Then you want to run sendline to send a line to the program. See the example:
http://pexpect.readthedocs.io/en/latest/overview.html
Hope that helps, and seriously, have a look at paramiko ;)