{"id":24617982,"url":"https://github.com/joknarf/pywebexec","last_synced_at":"2025-06-28T01:05:32.102Z","repository":{"id":271577485,"uuid":"913899533","full_name":"joknarf/pywebexec","owner":"joknarf","description":"Simple and Powerful Python HTTP(S) API/Web interface to Terminal share / Remote execution","archived":false,"fork":false,"pushed_at":"2025-04-17T19:36:55.000Z","size":9676,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-07T05:49:15.961Z","etag":null,"topics":["ansible-killer","api-server","batch-manager","https-server","parallel-execution","remote-command","swagger-ui","terminal","terminal-share","tty","web-interface","webserver","xterm"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/joknarf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-01-08T15:09:42.000Z","updated_at":"2025-04-17T19:34:26.000Z","dependencies_parsed_at":"2025-01-08T16:42:12.673Z","dependency_job_id":"c1f3287b-d730-4966-b410-c437413532a6","html_url":"https://github.com/joknarf/pywebexec","commit_stats":null,"previous_names":["joknarf/pywebexec"],"tags_count":249,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joknarf%2Fpywebexec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joknarf%2Fpywebexec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joknarf%2Fpywebexec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joknarf%2Fpywebexec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joknarf","download_url":"https://codeload.github.com/joknarf/pywebexec/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joknarf%2Fpywebexec/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":258895773,"owners_count":22774413,"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":["ansible-killer","api-server","batch-manager","https-server","parallel-execution","remote-command","swagger-ui","terminal","terminal-share","tty","web-interface","webserver","xterm"],"created_at":"2025-01-24T23:41:53.091Z","updated_at":"2025-06-28T01:05:32.075Z","avatar_url":"https://github.com/joknarf.png","language":"JavaScript","readme":"[![Pypi version](https://img.shields.io/pypi/v/pywebexec.svg)](https://pypi.org/project/pywebexec/)\n![Publish Package](https://github.com/joknarf/pywebexec/actions/workflows/python-publish.yml/badge.svg)\n[![Licence](https://img.shields.io/badge/licence-MIT-blue.svg)](https://shields.io/)\n[![PyPI Downloads](https://static.pepy.tech/badge/pywebexec)](https://pepy.tech/projects/pywebexec)\n[![Python versions](https://img.shields.io/badge/python-3.6+-blue.svg)](https://shields.io/)\n\n# pywebexec\nSimple Python HTTP(S) API/Web Server Command Launcher and Terminal sharing\n\n* build a Restfull API/swagger-ui powered application in no time exposing simple commands/parameters.\n* create a toolbox with batch management/parallel execution of commands\n* share a terminal in one command\n  \n## Install\n```\n$ pip install pywebexec\n```\n\n## Quick start\n\n* share terminal\n  * start http server and spawn a new terminal shared on 0.0.0.0 port 8080 (defaults)\n  * exiting terminal stops server/share\n```shell\n$ pywebexec shareterm\n```\n\n* serve executables\n  * put in a directory the scripts/commands/links to commands you want to expose\n  * start http server serving current directory executables listening on 0.0.0.0 port 8080\n```shell\n$ pywebexec -d \u003cdir\u003e\n```\n\n* Launch commands with params/view live output/Status using browser\n* Share your terminal output using `pywebexec -d \u003cdir\u003e term`\n\n![pywebexecnew11](https://github.com/user-attachments/assets/5acb15a7-92a4-4711-9de7-630721cbf47a)\n\nall commands output / statuses are available in the executables directory in subdirectory `.web_status`\n\n## features\n\n* Serve executables in a directory\n* full API driven with dynamic swagger UI\n* Launch commands with params from web browser or API call\n* multiple share terminal output\n* Follow live output\n* Replay terminal history\n* Stop command\n* Relaunch command\n* HTTPS support\n* HTTPS self-signed certificate generator\n* Basic Auth\n* LDAP(S) password check/group member\n* Safe url token generation\n* Can be started as a daemon (POSIX)\n* Uses gunicorn to serve http/https\n* Linux/MacOS compatible\n* Markdown help for commands\n* YAML schema for commands parameters\n* Batch/parallel command execution\n\n## Customize server\n```shell\n$ pywebexec --dir ~/myscripts --listen 0.0.0.0 --port 8080 --title myscripts\n$ pywebexec -d ~/myscripts -l 0.0.0.0 -p 8080 -t myscripts\n```\n\n## Sharing terminals\n\n* start server and share tty in one command\n```shell\n$ pywebexec -d ~/webshare shareterm\n```\n* share tty with an already pywebexec server started\n```shell\n$ pywebexec -d ~/webshare term\n```\nif another user need to share his terminal, he need to have write permission on `\u003cdir\u003e/.web_status` directory.\n\n## Safe url token\n\n* generate safe url, use the url to access the server\n```shell\n$ pywebexec -T\n$ pywebexec --tokenurl\nStarting server:\nhttp://\u003chost\u003e:8080?token=jSTWiNgEVkddeEJ7I97x2ekOeaiXs2mErRSKNxm3DP0\nhttp://x.x.x.x:8080?token=jSTWiNgEVkddeEJ7I97x2ekOeaiXs2mErRSKNxm3DP0\n```\n\n## Basic auth\n\n* single user/password\n```shell\n$ pywebexec --user myuser [--password mypass]\n$ pywebexec -u myuser [-P mypass]\n```\nGenerated password is given if no `--pasword` option\n\n* ldap(s) password check / group member\nldap server must accept memberOf attribute for group members\n```shell\n$ export PYWEBEXEC_LDAP_SERVER=ldaps://ldap.mydomain.com:389\n$ export PYWEBEXEC_LDAP_BIND_DN=\"cn=read-only-admin,dc=example,dc=com\"\n$ export PYWEBEXEC_LDAP_BIND_PASSWORD=\"password\"\n$ export PYWEBEXEC_LDAP_BASE_DN=\"dc=example,dc=com\"\n$ export PYWEBEXEC_LDAP_USER_ID=\"uid\" # sAMAccountName for AD\n$ export PYWEBEXEC_LDAP_GROUPS=\"ou=mathematicians,dc=example,dc=com ou=scientists,dc=example,dc=com\"\n$ pywebexec\n```\n## HTTPS server\n\n* Generate auto-signed certificate and start https server\n```shell\n$ pywebexec --gencert\n$ pywebexec --g\n```\n\n* Start https server using existing certificate\n```shell\n$ pywebexec --cert /pathto/host.cert --key /pathto/host.key\n$ pywebexec -c /pathto/host.cert -k /pathto/host.key\n```\n\n## Launch server as a daemon\n\n```shell\n$ pywebexec start\n$ pywebexec status\n$ pywebexec stop\n```\n* log of server are stored in directory `~/[.config/].pywebexec/pywebexec_\u003clisten\u003e:\u003cport\u003e.log`\n\n## Launch command through API\n\n```shell\n$ curl http://myhost:8080/commands/myscript -H 'Content-Type: application/json' -X POST -d '{\"params\":[\"param1\", ...]}'\n$ curl http://myhost:8080/commands/\u003ccommand_id\u003e\n$ curl http://myhost:8080/commands/\u003ccommand_id\u003e/output -H \"Accept: text/plain\"\n```\n\n## Add markdown help to commands\n\nFor each exposed command, you can add a help message by creating a file named `\u003ccommand\u003e.help` in the same directory as the command. The help message must be written in markdown.  \nThe help message is displayed:\n* in the web interface as tooltip when focused on param input field,\n* in the response when calling the API `/executables`\n* in the swagger-ui in the `/commands/\u003ccommand\u003e` route.\n\n\u003cimg src=\"https://github.com/user-attachments/assets/2d69cef2-3371-4282-99bb-e994eb0c0b24\" width=\"400\"/\u003e\n\n## Add schema to commands\n\nFor each exposed command, you can add a schema by creating a file named `\u003ccommand\u003e.schema.yaml` in the same directory as the command. The schema must be written in yaml format.  \nThe schema is used to generate a form in the web interface and in the swagger-ui in the `/commands/\u003ccommand\u003e` route.  \nThe schema is also used to validate the input parameters when calling the API `/commands/\u003ccommand\u003e`.  \nThe schema must be written in the openapi schema format.\n\n```yaml\ntype: object\nproperties:\n  param1:\n    type: string\n    description: \"param1 description\"\n    example: \"value\"\n  param2:\n    type: integer\n    description: \"param2 description\"\n    enum: [1, 2, 3]\n  param3:\n    type: array\n    items:\n      type: string\n    description: \"param3 description\"\n    example: [\"value1\", \"value2\"]\nrequired:\n  - param1\n  - param2\n```\nThe payload will be converted to command line arguments when calling the command.\n```\ncommand --param1 value --param2 1 --param3 value1 value2\n```\n\n* On the web inferface, and swagger-ui the form will be generated from the schema.\n\n\u003cimg src=\"https://github.com/user-attachments/assets/c7cdf117-aa38-4366-97c7-1aa26e5ebf0d\" width=\"400\"\u003e\n\nWhen using schema, the command can now be launched with:\n```\n$ curl -X POST http://\u003csrv\u003e/commands/\u003ccmd\u003e -H \"Content-Type: application/json\" -d '{\"param1\": \"value\", \"param2\": 1, \"param3\": [\"value1\", \"value2\"]}'\n```\n\n## Schema options\n\nThe schema options are used to customize the command line arguments generation, just add a `schema_options` section to the schema.\n```yaml\nschema_options:\n  separator_params: {\"*\": \" \", \"param2\": \"=\"}}\"=\" # --param2=value (default is \" \") \n  noprefix_params: [\"param1\", \"param2\"] # omit --param prefix, use \"*\" to omit all\n  convert_params: {\"param1\": \"param2\"} # convert param1 to param2\n```\n\n## Batch commands/parallel execution\n\nIntegration of [run-para](https://github.com/joknarf/run-para) to enable batch execution of commands:\n* In `schema_options` adding `batch_param` will enable batch mode for the command, the command will be executed for each value in the `batch_param` list.  \n* The `batch_param` is the name of the parameter that will be used to pass the different values for the parameter.  \n* The `batch_param` type will be transformed to textarea to provide list to use as parameter for the command.  \n* The range parameters `parallel` and `delay` is added to the command parameters to control the execution of the batch commands (nb jobs in parallel and initial delay between jobs). \n\n\u003cimg src=\"https://github.com/user-attachments/assets/a25bf197-5c2e-4cec-9dd7-53f83c11656f\" width=\"400\"\u003e\n\n\n## Swagger UI\n\nA custom swagger UI is available at `http[s]://\u003csrv\u003e/v0/documentation` with enhanced markdown rendering and form generation for body parameters.\n\n\u003cimg src=\"https://github.com/user-attachments/assets/c80a341e-c04c-4606-9510-a57b473a74e5\" width=\"400\"/\u003e\n\n\u003cimg src=\"https://github.com/user-attachments/assets/22261048-459e-4ace-8d04-c568d67bef37\" width=\"400\"\u003e\n\n\n## API reference\n\n\n| method    | route                       | params/payload     | returns\n|-----------|-----------------------------|--------------------|---------------------|\n| GET       | /commands/exposed           |                    | commands: [\u003cbr\u003e\u0026nbsp;\u0026nbsp;{\u003cbr\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;command: str,\u003cbr\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;help: str\u003cbr\u003e\u0026nbsp;\u0026nbsp;},\u003cbr\u003e]        |\n| GET       | /commands                   |                    | commands: [\u003cbr\u003e\u0026nbsp;\u0026nbsp;{\u003cbr\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;command_id: uuid\u003cbr\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;command: str\u003cbr\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;start_time: isotime\u003cbr\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;end_time: isotime\u003cbr\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;status: str\u003cbr\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;exit_code: int\u003cbr\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;last_output_line: str\u003cbr\u003e\u0026nbsp;\u0026nbsp;},\u003cbr\u003e]      |\n| GET       | /commands/{id}              |                    | command_id: uuid\u003cbr\u003ecommand: str\u003cbr\u003eparams: array[str]\u003cbr\u003estart_time: isotime\u003cbr\u003eend_time: isotime\u003cbr\u003estatus: str\u003cbr\u003eexit_code: int\u003cbr\u003elast_output_line: str      |\n| GET       | /commands/{id}/output       | offset: int        | output: str\u003cbr\u003estatus: str\u003cbr\u003elinks: { next: str }         |\n| GET       | /commands/{id}/output_raw   | offset: int        | output: stream raw output until end of command\u003cbr\u003ecurl -Ns http://srv/commands/{id}/output_raw|\n| POST      | /commands                   | command: str\u003cbr\u003eparams: array[str]\u003cbr\u003erows: int\u003cbr\u003ecols: int       | command_id: uuid\u003cbr\u003emessage: str    |\n| POST      | /commands/{cmd}             | params: array[str]\u003cbr\u003erows: int\u003cbr\u003ecols: int       | command_id: uuid\u003cbr\u003emessage: str    |\n| PATCH     | /commands/{id}/stop        |                    | message: str        |\n\n* to get command output as text (without ANSI codes/Control characters) use: `/commands/{id}/output` with header `\"Accept: text/plain\"`\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoknarf%2Fpywebexec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoknarf%2Fpywebexec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoknarf%2Fpywebexec/lists"}