1

I am writing some code in Python which checks for the validity of a license key after polling a server. If it is valid then the Python program in turn runs some bash scripts.

How to create a combined binary of the python script (to check the license) and the bash script (which performs the task)?

Here are what I think could be the solutions but I am really not sure:

  1. I use the encode function in python and encode the bash script file once and add combine that file and the license_checker.py file into a single binary. When the binary runs, the python code should decode the file into a temp file, run the script and delete the temp file.
  2. Find a mechanism which wraps/embeds the bash code in the python script. I have heard of decorators but I haven't used them and do not know if they would serve the purpose.
  • I'd go the first route; the second won't work as decorators are syntactic sugar for creating wrapper functions for other functions (e.g. Python code wrapping Python code). – Martijn Pieters Aug 8 '13 at 9:07
5

I'd use the first option; embed the bash script in a multi-line string in the Python script, then write that out and use the subprocess module to run the script:

import tempfile
import subprocess

script_one = '''\
echo "Hello world!"
echo "This is a bash script. :-)"
'''

def run_script(script):
    with tempfile.NamedTemporaryFile() as scriptfile:
        scriptfile.write(script)
        scriptfile.flush()
        subprocess.call(['/bin/bash', scriptfile.name])

run_script(script_one)

The run_script() function takes a bash script source, writes it to a temporary file, executes it, and automatically cleans up the temporary file when done.

Demo:

$ python /tmp/scripttest.py 
Hello world!
This is a bash script. :-)

Python decorators are of no help here; there is no point in looking at those; decorators are simply Python functions that get to wrap other Python functions.

If the script is large, you could try compressing it with zlib, base64 encode it, then embed that into the Python script file; using .decode('base64') and passing the result to the zlib module first gives you a decompressed string again. The ZLIB compression reduces the size but results in binary data, always a little harder to embed without having to deal with proper escaping and line lengths. The Base64 encoding turns the binary data into multi-line ASCII-safe data again, albeit at the price of 25% more bytes:

>>> import zlib
>>> zlib.compress(script_one).encode('base64')
'eJxLTc7IV1DySM3JyVcozy/KSVFU4koFi4VkZBYrAFGiQlJicYZCcXJRZkGJnoKVrqYSFwDnexDe\n'
>>> print """script_one = '''\\\n{}'''""".format(_)
script_one = '''\
eJxLTc7IV1DySM3JyVcozy/KSVFU4koFi4VkZBYrAFGiQlJicYZCcXJRZkGJnoKVrqYSFwDnexDe
'''

Note that for this short script sample, this increased the size, from 54 characters to 77, but for longer scripts you should see a decent size reduction.

Decompression is then as simple as zlib.decompress(script_one.decode('base64'))

  • said bash script is around 200 lines.... :( – rahuL Aug 8 '13 at 9:21
  • 1
    @i.h4d35: Why not use a separate file then? – Martijn Pieters Aug 8 '13 at 9:23
  • On a separate note, is it favourable that I maybe encode the bash script (using .encode('base64') function) and embed that in the python script? Sorry to sound silly, I'm just asking for a security point-of-view of the product. Or is there any other suggested method? – rahuL Aug 8 '13 at 9:26
  • Only base64 encoding will expand the size, not reduce it. – Martijn Pieters Aug 8 '13 at 9:27
  • So to summarize, compress bash with gzip, base64 encode it, embed that as a string in the python script; in the python script, decode it pass the result through gzip module and then pass this whole sting to the run_script function - is this right? – rahuL Aug 8 '13 at 9:33

protected by gnat Aug 27 '18 at 13:17

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.