shellsafe 0.1.0__tar.gz → 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. {shellsafe-0.1.0 → shellsafe-0.1.1}/CHANGELOG.md +8 -0
  2. shellsafe-0.1.1/PKG-INFO +128 -0
  3. shellsafe-0.1.1/README.md +106 -0
  4. {shellsafe-0.1.0 → shellsafe-0.1.1}/pyproject.toml +1 -1
  5. shellsafe-0.1.1/src/shellsafe/_version.py +1 -0
  6. shellsafe-0.1.1/tests/unit/test_raw.py +15 -0
  7. shellsafe-0.1.0/PKG-INFO +0 -126
  8. shellsafe-0.1.0/README.md +0 -104
  9. shellsafe-0.1.0/src/shellsafe/_version.py +0 -1
  10. shellsafe-0.1.0/tests/unit/test_raw.py +0 -28
  11. {shellsafe-0.1.0 → shellsafe-0.1.1}/.github/workflows/ci.yml +0 -0
  12. {shellsafe-0.1.0 → shellsafe-0.1.1}/.github/workflows/release.yml +0 -0
  13. {shellsafe-0.1.0 → shellsafe-0.1.1}/.gitignore +0 -0
  14. {shellsafe-0.1.0 → shellsafe-0.1.1}/CONTRIBUTING.md +0 -0
  15. {shellsafe-0.1.0 → shellsafe-0.1.1}/LICENSE +0 -0
  16. {shellsafe-0.1.0 → shellsafe-0.1.1}/examples/demo.py +0 -0
  17. {shellsafe-0.1.0 → shellsafe-0.1.1}/src/shellsafe/__init__.py +0 -0
  18. {shellsafe-0.1.0 → shellsafe-0.1.1}/src/shellsafe/__main__.py +0 -0
  19. {shellsafe-0.1.0 → shellsafe-0.1.1}/src/shellsafe/audit/__init__.py +0 -0
  20. {shellsafe-0.1.0 → shellsafe-0.1.1}/src/shellsafe/audit/rules.py +0 -0
  21. {shellsafe-0.1.0 → shellsafe-0.1.1}/src/shellsafe/cli.py +0 -0
  22. {shellsafe-0.1.0 → shellsafe-0.1.1}/src/shellsafe/errors.py +0 -0
  23. {shellsafe-0.1.0 → shellsafe-0.1.1}/src/shellsafe/execute.py +0 -0
  24. {shellsafe-0.1.0 → shellsafe-0.1.1}/src/shellsafe/exitcodes.py +0 -0
  25. {shellsafe-0.1.0 → shellsafe-0.1.1}/src/shellsafe/platforms.py +0 -0
  26. {shellsafe-0.1.0 → shellsafe-0.1.1}/src/shellsafe/py.typed +0 -0
  27. {shellsafe-0.1.0 → shellsafe-0.1.1}/src/shellsafe/raw.py +0 -0
  28. {shellsafe-0.1.0 → shellsafe-0.1.1}/src/shellsafe/render.py +0 -0
  29. {shellsafe-0.1.0 → shellsafe-0.1.1}/src/shellsafe/reporters.py +0 -0
  30. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/golden/.gitkeep +0 -0
  31. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/integration/.gitkeep +0 -0
  32. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/integration/test_exec_posix.py +0 -0
  33. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/payloads/cases/README.md +0 -0
  34. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/payloads/cases/case_01_semicolon.txt +0 -0
  35. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/payloads/cases/case_02_substitution.txt +0 -0
  36. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/payloads/cases/case_03_backticks.txt +0 -0
  37. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/payloads/cases/case_04_background_chain.txt +0 -0
  38. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/payloads/cases/case_05_or_chain.txt +0 -0
  39. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/payloads/cases/case_06_redirect_out.txt +0 -0
  40. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/payloads/cases/case_07_redirect_in.txt +0 -0
  41. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/payloads/cases/case_08_pipe_out.txt +0 -0
  42. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/payloads/cases/case_09_quote_smuggle.txt +0 -0
  43. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/payloads/cases/case_10_quote_storm.txt +0 -0
  44. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/payloads/cases/case_11_globs_expansions.txt +0 -0
  45. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/payloads/cases/case_12_newline.txt +0 -0
  46. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/payloads/cases/case_13_fullwidth_semicolon.txt +0 -0
  47. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/payloads/cases/case_14_whitespace.txt +0 -0
  48. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/payloads/cases/case_15_unicode_dashes.txt +0 -0
  49. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/property/.gitkeep +0 -0
  50. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/property/test_invariants.py +0 -0
  51. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/unit/test_cli.py +0 -0
  52. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/unit/test_errors.py +0 -0
  53. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/unit/test_payload_corpus.py +0 -0
  54. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/unit/test_public_surface.py +0 -0
  55. {shellsafe-0.1.0 → shellsafe-0.1.1}/tests/unit/test_render.py +0 -0
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project are documented here. Format follows
4
4
  Keep a Changelog; versioning follows SemVer.
5
5
 
6
+ ## [0.1.1] - 2026-08-24
7
+
8
+ ### Changed
9
+
10
+ - Project description rewritten
11
+ - README restructured for PyPI: package page now leads with the why, usage and
12
+ limits; contributing details stay in the repository only
13
+
6
14
  ## [0.1.0] - 2026-08-24
7
15
 
8
16
  ### Added
@@ -0,0 +1,128 @@
1
+ Metadata-Version: 2.5
2
+ Name: shellsafe
3
+ Version: 0.1.1
4
+ Summary: Run shell commands safely using Python 3.14 template strings. Values can never turn into commands.
5
+ Project-URL: Repository, https://github.com/rahulXs/shellsafe
6
+ Project-URL: Issues, https://github.com/rahulXs/shellsafe/issues
7
+ Project-URL: Changelog, https://github.com/rahulXs/shellsafe/blob/main/CHANGELOG.md
8
+ Author-email: Rahul Sharma <rahulxsh@gmail.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: automation,command-injection,injection,pep750,security,shell,subprocess,t-strings,template-strings
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Topic :: Security
18
+ Classifier: Topic :: Software Development :: Libraries
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.14
21
+ Description-Content-Type: text/markdown
22
+
23
+ # shellsafe
24
+
25
+ > Run shell commands safely using Python 3.14 template strings. Values can never
26
+ > turn into commands.
27
+
28
+ ```python
29
+ from shellsafe import run
30
+
31
+ message = get_user_input() # "fix; rm -rf ~"
32
+ run(t"git commit -m {message}")
33
+ # argv: ["git", "commit", "-m", "fix; rm -rf ~"]
34
+ # one command; the scary text is just an argument
35
+ ```
36
+
37
+ ## Why this package exists
38
+
39
+ Python 3.14 added template strings (PEP 750). Now Python keeps your fixed text
40
+ and your values separate at the language level.
41
+
42
+ Shell commands are the first place people want to use this. That is because
43
+ f-strings inside shell commands have caused real security bugs for ten years:
44
+
45
+ ```python
46
+ subprocess.run(f"git commit -m {message}", shell=True)
47
+ # if message = "fix; rm -rf ~" -> two commands run. The second one is bad.
48
+ ```
49
+
50
+ Python planned to solve this officially (PEP 787), but that plan was postponed.
51
+ So today there is no standard way to run shell commands safely with templates.
52
+ This package fills that gap.
53
+
54
+ ## Install
55
+
56
+ ```bash
57
+ pip install shellsafe
58
+ ```
59
+
60
+ Needs Python 3.14 or newer.
61
+
62
+ ## How to use
63
+
64
+ Run a command. Your values always stay one argument each:
65
+
66
+ ```python
67
+ from shellsafe import run
68
+
69
+ run(t"mkdir {path}")
70
+ run(t"docker build -t {tag} .", check=True, timeout=300)
71
+ ```
72
+
73
+ Get the output as text:
74
+
75
+ ```python
76
+ from shellsafe import capture
77
+
78
+ res = capture(t"grep {pattern} {file}")
79
+ print(res.stdout, res.returncode)
80
+ ```
81
+
82
+ Need pipes? Works on Linux and macOS. Your values are quoted safely first:
83
+
84
+ ```python
85
+ from shellsafe import shx
86
+
87
+ shx(t"cat {file} | wc -l")
88
+ ```
89
+
90
+ Want to see exactly what will run?
91
+
92
+ ```python
93
+ from shellsafe import plan
94
+
95
+ print(plan(t"git commit -m {message}"))
96
+ # argv: ["git","commit","-m","fix; rm -rf ~"]
97
+ ```
98
+
99
+ ## Safety rules
100
+
101
+ | Case | What happens |
102
+ |---|---|
103
+ | Any value you pass | becomes one argument, exactly as given |
104
+ | Value used as the program name | error: program names must be written as fixed text |
105
+ | Shell features on Windows | error: we cannot make Windows safe this way, so we say no |
106
+ | RAW() misuse | error: one value only, used as-is, no nesting |
107
+
108
+ `RAW(...)` marks content you have already made safe by hand. It is loud and easy
109
+ to find in code review, so trust is never hidden.
110
+
111
+ ## Limits
112
+
113
+ - On Windows, commands with pipes do not work. Plain commands work fully.
114
+ - Byte values are rejected. Decode them first.
115
+ - We keep your command safe to build and run. Testing what your command does is
116
+ still your job.
117
+
118
+ ## Needs
119
+
120
+ - Python 3.14 or newer
121
+ - Linux, macOS, Windows (pipes work on Linux and macOS only)
122
+
123
+ ## More
124
+
125
+ - Source and issues: [github.com/rahulXs/shellsafe](https://github.com/rahulXs/shellsafe)
126
+ - Want to help? See CONTRIBUTING.md in the repository.
127
+
128
+ License: MIT
@@ -0,0 +1,106 @@
1
+ # shellsafe
2
+
3
+ > Run shell commands safely using Python 3.14 template strings. Values can never
4
+ > turn into commands.
5
+
6
+ ```python
7
+ from shellsafe import run
8
+
9
+ message = get_user_input() # "fix; rm -rf ~"
10
+ run(t"git commit -m {message}")
11
+ # argv: ["git", "commit", "-m", "fix; rm -rf ~"]
12
+ # one command; the scary text is just an argument
13
+ ```
14
+
15
+ ## Why this package exists
16
+
17
+ Python 3.14 added template strings (PEP 750). Now Python keeps your fixed text
18
+ and your values separate at the language level.
19
+
20
+ Shell commands are the first place people want to use this. That is because
21
+ f-strings inside shell commands have caused real security bugs for ten years:
22
+
23
+ ```python
24
+ subprocess.run(f"git commit -m {message}", shell=True)
25
+ # if message = "fix; rm -rf ~" -> two commands run. The second one is bad.
26
+ ```
27
+
28
+ Python planned to solve this officially (PEP 787), but that plan was postponed.
29
+ So today there is no standard way to run shell commands safely with templates.
30
+ This package fills that gap.
31
+
32
+ ## Install
33
+
34
+ ```bash
35
+ pip install shellsafe
36
+ ```
37
+
38
+ Needs Python 3.14 or newer.
39
+
40
+ ## How to use
41
+
42
+ Run a command. Your values always stay one argument each:
43
+
44
+ ```python
45
+ from shellsafe import run
46
+
47
+ run(t"mkdir {path}")
48
+ run(t"docker build -t {tag} .", check=True, timeout=300)
49
+ ```
50
+
51
+ Get the output as text:
52
+
53
+ ```python
54
+ from shellsafe import capture
55
+
56
+ res = capture(t"grep {pattern} {file}")
57
+ print(res.stdout, res.returncode)
58
+ ```
59
+
60
+ Need pipes? Works on Linux and macOS. Your values are quoted safely first:
61
+
62
+ ```python
63
+ from shellsafe import shx
64
+
65
+ shx(t"cat {file} | wc -l")
66
+ ```
67
+
68
+ Want to see exactly what will run?
69
+
70
+ ```python
71
+ from shellsafe import plan
72
+
73
+ print(plan(t"git commit -m {message}"))
74
+ # argv: ["git","commit","-m","fix; rm -rf ~"]
75
+ ```
76
+
77
+ ## Safety rules
78
+
79
+ | Case | What happens |
80
+ |---|---|
81
+ | Any value you pass | becomes one argument, exactly as given |
82
+ | Value used as the program name | error: program names must be written as fixed text |
83
+ | Shell features on Windows | error: we cannot make Windows safe this way, so we say no |
84
+ | RAW() misuse | error: one value only, used as-is, no nesting |
85
+
86
+ `RAW(...)` marks content you have already made safe by hand. It is loud and easy
87
+ to find in code review, so trust is never hidden.
88
+
89
+ ## Limits
90
+
91
+ - On Windows, commands with pipes do not work. Plain commands work fully.
92
+ - Byte values are rejected. Decode them first.
93
+ - We keep your command safe to build and run. Testing what your command does is
94
+ still your job.
95
+
96
+ ## Needs
97
+
98
+ - Python 3.14 or newer
99
+ - Linux, macOS, Windows (pipes work on Linux and macOS only)
100
+
101
+ ## More
102
+
103
+ - Source and issues: [github.com/rahulXs/shellsafe](https://github.com/rahulXs/shellsafe)
104
+ - Want to help? See CONTRIBUTING.md in the repository.
105
+
106
+ License: MIT
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
5
5
  [project]
6
6
  name = "shellsafe"
7
7
  dynamic = ["version"]
8
- description = "Safe shell commands via Python 3.14 template strings. Injection-proof by construction."
8
+ description = "Run shell commands safely using Python 3.14 template strings. Values can never turn into commands."
9
9
  readme = "README.md"
10
10
  license = "MIT"
11
11
  requires-python = ">=3.14"
@@ -0,0 +1 @@
1
+ __version__ = "0.1.1"
@@ -0,0 +1,15 @@
1
+ """RAW marker invariants: nesting refused, verbatim display, single argument."""
2
+
3
+ import pytest
4
+
5
+ from shellsafe import RAW
6
+ from shellsafe.errors import RawUsageError
7
+
8
+
9
+ def test_raw_repr_shows_trust_boundary():
10
+ assert "<RAW" in repr(RAW("pre-quoted"))
11
+
12
+
13
+ def test_nested_raw_refused():
14
+ with pytest.raises(RawUsageError):
15
+ RAW(RAW(["x"]))
shellsafe-0.1.0/PKG-INFO DELETED
@@ -1,126 +0,0 @@
1
- Metadata-Version: 2.5
2
- Name: shellsafe
3
- Version: 0.1.0
4
- Summary: Safe shell commands via Python 3.14 template strings. Injection-proof by construction.
5
- Project-URL: Repository, https://github.com/rahulXs/shellsafe
6
- Project-URL: Issues, https://github.com/rahulXs/shellsafe/issues
7
- Project-URL: Changelog, https://github.com/rahulXs/shellsafe/blob/main/CHANGELOG.md
8
- Author-email: Rahul Sharma <rahulxsh@gmail.com>
9
- License-Expression: MIT
10
- License-File: LICENSE
11
- Keywords: automation,command-injection,injection,pep750,security,shell,subprocess,t-strings,template-strings
12
- Classifier: Development Status :: 3 - Alpha
13
- Classifier: Intended Audience :: Developers
14
- Classifier: License :: OSI Approved :: MIT License
15
- Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3.14
17
- Classifier: Topic :: Security
18
- Classifier: Topic :: Software Development :: Libraries
19
- Classifier: Typing :: Typed
20
- Requires-Python: >=3.14
21
- Description-Content-Type: text/markdown
22
-
23
- # shellsafe
24
-
25
- > Safe shell commands via Python 3.14 template strings. Injection-proof by
26
- > construction.
27
-
28
- ```python
29
- from shellsafe import run
30
-
31
- message = get_user_input() # "fix; rm -rf ~"
32
- run(t"git commit -m {message}")
33
- # argv: ["git", "commit", "-m", "fix; rm -rf ~"]
34
- # one command; the scary text is just an argument
35
- ```
36
-
37
- ## Why
38
-
39
- The dominant pattern in scripts and automation is still this:
40
-
41
- ```python
42
- subprocess.run(f"git commit -m {message}", shell=True) # injection waiting to happen
43
- ```
44
-
45
- Python 3.14 template strings (`t"..."`) separate static text from interpolated
46
- values. shellsafe turns that structure into argv lists where interpolated values
47
- are always data, never commands. When you genuinely need pipes, shell mode quotes
48
- every value with POSIX rules first.
49
-
50
- ## Install
51
-
52
- ```bash
53
- pip install shellsafe
54
- ```
55
-
56
- Requires Python 3.14+ (template strings).
57
-
58
- ## Usage
59
-
60
- Run a command. Interpolated values are always single arguments:
61
-
62
- ```python
63
- from shellsafe import run
64
-
65
- run(t"mkdir {path}")
66
- run(t"docker build -t {tag} .", check=True, timeout=300)
67
- ```
68
-
69
- Capture output as text:
70
-
71
- ```python
72
- from shellsafe import capture
73
-
74
- res = capture(t"grep {pattern} {file}")
75
- print(res.stdout, res.returncode)
76
- ```
77
-
78
- Pipes and redirections on POSIX (values are quoted with `shlex.quote` first):
79
-
80
- ```python
81
- from shellsafe import shx
82
-
83
- shx(t"cat {file} | wc -l")
84
- ```
85
-
86
- Inspect exactly what will execute:
87
-
88
- ```python
89
- from shellsafe import plan # lower-level: render without running
90
-
91
- print(plan(t"git commit -m {message}"))
92
- # argv: ["git","commit","-m","fix; rm -rf ~"]
93
- ```
94
-
95
- ## What it refuses
96
-
97
- | Case | Behavior |
98
- |---|---|
99
- | Interpolation as the executable | error: the command comes from static text only |
100
- | Shell route on Windows | error: cmd.exe quoting cannot be made injection-safe; use argv mode |
101
- | RAW misuse | error: one argument, verbatim, nesting refused |
102
-
103
- `RAW("...")` / `RAW(["a", "b"])` is the single explicit trust boundary for
104
- pre-quoted content. Every use site is greppable.
105
-
106
- ## Limits
107
-
108
- - Windows: interpolated shell routes are refused rather than approximated;
109
- argv-mode commands work fully.
110
- - Bytes interpolations are rejected: decode explicitly first.
111
- - Runtime behavior after import is your test suite's job, same trust model as
112
- calling subprocess yourself.
113
-
114
- ## Contributing
115
-
116
- Issues and PRs welcome. Security reports go privately to the maintainer, never
117
- through public issues.
118
-
119
- ## Requirements
120
-
121
- - CPython >= 3.14 (uses template strings from PEP 750)
122
- - Linux, macOS, Windows (Windows supports argv mode; POSIX-only shell mode)
123
-
124
- ## License
125
-
126
- MIT
shellsafe-0.1.0/README.md DELETED
@@ -1,104 +0,0 @@
1
- # shellsafe
2
-
3
- > Safe shell commands via Python 3.14 template strings. Injection-proof by
4
- > construction.
5
-
6
- ```python
7
- from shellsafe import run
8
-
9
- message = get_user_input() # "fix; rm -rf ~"
10
- run(t"git commit -m {message}")
11
- # argv: ["git", "commit", "-m", "fix; rm -rf ~"]
12
- # one command; the scary text is just an argument
13
- ```
14
-
15
- ## Why
16
-
17
- The dominant pattern in scripts and automation is still this:
18
-
19
- ```python
20
- subprocess.run(f"git commit -m {message}", shell=True) # injection waiting to happen
21
- ```
22
-
23
- Python 3.14 template strings (`t"..."`) separate static text from interpolated
24
- values. shellsafe turns that structure into argv lists where interpolated values
25
- are always data, never commands. When you genuinely need pipes, shell mode quotes
26
- every value with POSIX rules first.
27
-
28
- ## Install
29
-
30
- ```bash
31
- pip install shellsafe
32
- ```
33
-
34
- Requires Python 3.14+ (template strings).
35
-
36
- ## Usage
37
-
38
- Run a command. Interpolated values are always single arguments:
39
-
40
- ```python
41
- from shellsafe import run
42
-
43
- run(t"mkdir {path}")
44
- run(t"docker build -t {tag} .", check=True, timeout=300)
45
- ```
46
-
47
- Capture output as text:
48
-
49
- ```python
50
- from shellsafe import capture
51
-
52
- res = capture(t"grep {pattern} {file}")
53
- print(res.stdout, res.returncode)
54
- ```
55
-
56
- Pipes and redirections on POSIX (values are quoted with `shlex.quote` first):
57
-
58
- ```python
59
- from shellsafe import shx
60
-
61
- shx(t"cat {file} | wc -l")
62
- ```
63
-
64
- Inspect exactly what will execute:
65
-
66
- ```python
67
- from shellsafe import plan # lower-level: render without running
68
-
69
- print(plan(t"git commit -m {message}"))
70
- # argv: ["git","commit","-m","fix; rm -rf ~"]
71
- ```
72
-
73
- ## What it refuses
74
-
75
- | Case | Behavior |
76
- |---|---|
77
- | Interpolation as the executable | error: the command comes from static text only |
78
- | Shell route on Windows | error: cmd.exe quoting cannot be made injection-safe; use argv mode |
79
- | RAW misuse | error: one argument, verbatim, nesting refused |
80
-
81
- `RAW("...")` / `RAW(["a", "b"])` is the single explicit trust boundary for
82
- pre-quoted content. Every use site is greppable.
83
-
84
- ## Limits
85
-
86
- - Windows: interpolated shell routes are refused rather than approximated;
87
- argv-mode commands work fully.
88
- - Bytes interpolations are rejected: decode explicitly first.
89
- - Runtime behavior after import is your test suite's job, same trust model as
90
- calling subprocess yourself.
91
-
92
- ## Contributing
93
-
94
- Issues and PRs welcome. Security reports go privately to the maintainer, never
95
- through public issues.
96
-
97
- ## Requirements
98
-
99
- - CPython >= 3.14 (uses template strings from PEP 750)
100
- - Linux, macOS, Windows (Windows supports argv mode; POSIX-only shell mode)
101
-
102
- ## License
103
-
104
- MIT
@@ -1 +0,0 @@
1
- __version__ = "0.1.0"
@@ -1,28 +0,0 @@
1
- """RAW marker invariants: nesting refused, verbatim display, single argument."""
2
-
3
- import pytest
4
-
5
- from shellsafe import RAW
6
- from shellsafe.errors import RawUsageError
7
- from shellsafe.raw import Raw
8
-
9
-
10
- def test_raw_wraps_list_verbatim():
11
- r = RAW(["git", "log", "--oneline"])
12
- assert isinstance(r, Raw)
13
- assert r.value == ["git", "log", "--oneline"]
14
-
15
-
16
- def test_raw_repr_shows_trust_boundary():
17
- assert "<RAW" in repr(RAW("pre-quoted"))
18
-
19
-
20
- def test_nested_raw_refused():
21
- with pytest.raises(RawUsageError):
22
- RAW(RAW(["x"]))
23
-
24
-
25
- def test_raw_is_greppable():
26
- # house rule: trust boundaries are greppable; this documents the pattern
27
- source = 'RAW("trusted")'
28
- assert "RAW(" in source
File without changes
File without changes
File without changes
File without changes