Metadata-Version: 2.5
Name: shellsafe
Version: 0.1.1
Summary: Run shell commands safely using Python 3.14 template strings. Values can never turn into commands.
Project-URL: Repository, https://github.com/rahulXs/shellsafe
Project-URL: Issues, https://github.com/rahulXs/shellsafe/issues
Project-URL: Changelog, https://github.com/rahulXs/shellsafe/blob/main/CHANGELOG.md
Author-email: Rahul Sharma <rahulxsh@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: automation,command-injection,injection,pep750,security,shell,subprocess,t-strings,template-strings
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries
Classifier: Typing :: Typed
Requires-Python: >=3.14
Description-Content-Type: text/markdown

# shellsafe

> Run shell commands safely using Python 3.14 template strings. Values can never
> turn into commands.

```python
from shellsafe import run

message = get_user_input()          # "fix; rm -rf ~"
run(t"git commit -m {message}")
# argv: ["git", "commit", "-m", "fix; rm -rf ~"]
# one command; the scary text is just an argument
```

## Why this package exists

Python 3.14 added template strings (PEP 750). Now Python keeps your fixed text
and your values separate at the language level.

Shell commands are the first place people want to use this. That is because
f-strings inside shell commands have caused real security bugs for ten years:

```python
subprocess.run(f"git commit -m {message}", shell=True)
# if message = "fix; rm -rf ~"  ->  two commands run. The second one is bad.
```

Python planned to solve this officially (PEP 787), but that plan was postponed.
So today there is no standard way to run shell commands safely with templates.
This package fills that gap.

## Install

```bash
pip install shellsafe
```

Needs Python 3.14 or newer.

## How to use

Run a command. Your values always stay one argument each:

```python
from shellsafe import run

run(t"mkdir {path}")
run(t"docker build -t {tag} .", check=True, timeout=300)
```

Get the output as text:

```python
from shellsafe import capture

res = capture(t"grep {pattern} {file}")
print(res.stdout, res.returncode)
```

Need pipes? Works on Linux and macOS. Your values are quoted safely first:

```python
from shellsafe import shx

shx(t"cat {file} | wc -l")
```

Want to see exactly what will run?

```python
from shellsafe import plan

print(plan(t"git commit -m {message}"))
# argv: ["git","commit","-m","fix; rm -rf ~"]
```

## Safety rules

| Case | What happens |
|---|---|
| Any value you pass | becomes one argument, exactly as given |
| Value used as the program name | error: program names must be written as fixed text |
| Shell features on Windows | error: we cannot make Windows safe this way, so we say no |
| RAW() misuse | error: one value only, used as-is, no nesting |

`RAW(...)` marks content you have already made safe by hand. It is loud and easy
to find in code review, so trust is never hidden.

## Limits

- On Windows, commands with pipes do not work. Plain commands work fully.
- Byte values are rejected. Decode them first.
- We keep your command safe to build and run. Testing what your command does is
  still your job.

## Needs

- Python 3.14 or newer
- Linux, macOS, Windows (pipes work on Linux and macOS only)

## More

- Source and issues: [github.com/rahulXs/shellsafe](https://github.com/rahulXs/shellsafe)
- Want to help? See CONTRIBUTING.md in the repository.

License: MIT
