Tag Archives: python

Scripting ssh and git securely with Python

Some programs such as SSH ask for password and key passphrase via TTY (rather than STDIN), which is not supported by Python’s subprocess.Popen() call – the otherwise recommended, convenient way or running programs in a separate process.

This issue also arises when using SSH and PKI keys with git, to secure communications with a git server without an username and password.

This example illustrates use of pty.fork() from Python stdlib to support communications with a child process via a tty (a pty, actually).

"Run git clone using pki key with passphrase."
import pty, os, sys, select
def waitfor(fd, str):
"poll the child for input"
poll = select.poll()
poll.register(fd, select.POLLIN)
while True:
evt = poll.poll()
if str in os.read(fd, 1024):
if __name__=="__main__":
# run this from shell with git url,target path & key passphrase
giturl, path, passphrase = sys.argv[1:4]
pid, fd = pty.fork()
# executed in child
if pid == 0:
os.execvp("git", ["git", "clone", giturl, path])
# executed in parent
elif pid > 0:
waitfor(fd, "Enter passphrase")
os.write(fd, passphrase + "\n")
waitfor(fd, "Resolving deltas: 100%")
view raw gistfile1.py hosted with ❤ by GitHub

There’s also some more explanations on how pty.fork() works, from Stack Overflow. Furthermore, Paul Mikesell has written an extensive article on scripting SSH with Python.

Uploadify session workaround

Due to design of Flash that Uploadify uses, there is a known problem whereby the Flash component of Uploadify does not pass back the cookies. So things like sessions do not work as expected out-of-the-box.

Luckily, there’s a workaround: uploadify has a scriptData option that you can populate from the session cookie  (perhaps using a jQuery cookie plugin for convenience). The option value is then passed to the backend app, which can use it to switch to the proper session. For example as follows:

First, a small function to fetch the session id:

var sid = function () {
   return {'sessionid':$.cookie('sessionid')}

Then, as part of the Uploadify initialization, set scriptData to pass the return value:

$(document).ready(function() {
     'uploader'  : '/uploadify/uploadify.swf',
     'script'    : '/upload_files',
     'scriptData': sid(), // <--- our function

This is just an incomplete example; for the rest of the options you want to initialize Uploadify with, see Uploadify docs.
As for backend processing, scriptData comes in as regular POST variables. I was building a simple Django app when encountering this problem, so here’s what I did to fetch the session id and switch to another Django session using it.

# get session id that was passed in via scriptData
sid = request.POST['sessionid']

# Switch to another session by triggering the
# SessionStore session loading machinery, using
# the proper session id that we passed in from
# Uploadify.
session = request.session

That’s all.