pisces-cli 0.1.0__tar.gz → 0.1.2__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.
- pisces_cli-0.1.2/PKG-INFO +232 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/PYPI_README.md +51 -18
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/__init__.py +1 -1
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/init_cmd.py +28 -14
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/tui.py +1 -1
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pyproject.toml +2 -2
- pisces_cli-0.1.2/tests/test_init_cmd.py +34 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/uv.lock +1 -1
- pisces_cli-0.1.0/PKG-INFO +0 -448
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/.github/workflows/ci.yml +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/.github/workflows/pypi-publish.yml +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/.gitignore +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/.python-version +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/CONTRIBUTION.md +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/LICENSE +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/README.md +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/__main__.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/ast_visitor.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/cli.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/config_cmd.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/config_manager.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/context_manager.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/explain_cmd.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/fix_cmd.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/history_cmd.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/judge.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/llm_client.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/models.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/patch_engine.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/scan_cmd.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/scanner.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/watcher.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/requirements.txt +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/tests/__init__.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/tests/conftest.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/tests/test_config_manager.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/tests/test_context_manager.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/tests/test_models.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/tests/test_patch_engine.py +0 -0
- {pisces_cli-0.1.0 → pisces_cli-0.1.2}/tests/test_scanner.py +0 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pisces-cli
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: AI-assisted,self healing human-governed Python security remediation patcher
|
|
5
|
+
Project-URL: Homepage, https://github.com/richochetclementine1315/pisces
|
|
6
|
+
Project-URL: Repository, https://github.com/richochetclementine1315/pisces
|
|
7
|
+
Project-URL: Issues, https://github.com/richochetclementine1315/pisces/issues
|
|
8
|
+
Author-email: Mrinmoy Matilal <mrinmoymatilal1315@gmail.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ai,cli,llm,patcher,python,scanner,security,static-analysis,vulnerability
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Topic :: Security
|
|
22
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: anthropic>=0.28.0
|
|
25
|
+
Requires-Dist: bandit>=1.7.0
|
|
26
|
+
Requires-Dist: google-generativeai>=0.7.0
|
|
27
|
+
Requires-Dist: groq>=0.9.0
|
|
28
|
+
Requires-Dist: httpx>=0.27.0
|
|
29
|
+
Requires-Dist: jsonschema>=4.22.0
|
|
30
|
+
Requires-Dist: openai>=1.30.0
|
|
31
|
+
Requires-Dist: rich>=13.7.0
|
|
32
|
+
Requires-Dist: tomli>=2.0.0; python_version < '3.11'
|
|
33
|
+
Requires-Dist: typer>=0.12.0
|
|
34
|
+
Requires-Dist: watchdog>=4.0.0
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: mypy>=1.10.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
39
|
+
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
<p align="center">
|
|
43
|
+
<img src="https://github.com/user-attachments/assets/66723bfc-b15b-44bb-8dfa-cc74ff298ade"
|
|
44
|
+
width="280"
|
|
45
|
+
height="100"
|
|
46
|
+
alt="Pisces Banner">
|
|
47
|
+
</p>
|
|
48
|
+
|
|
49
|
+
<h1 align="center">PISCES</h1>
|
|
50
|
+
|
|
51
|
+
<p align="center">
|
|
52
|
+
<b>AI-Assisted · Self-Healing · Human-Governed Python Security Remediation Patcher</b>
|
|
53
|
+
</p>
|
|
54
|
+
|
|
55
|
+
<p align="center">
|
|
56
|
+
<a href="https://pypi.org/project/pisces-cli/">
|
|
57
|
+
<img src="https://img.shields.io/pypi/v/pisces-cli?color=7c3aed&logo=pypi&logoColor=white&label=PyPI" alt="PyPI Version">
|
|
58
|
+
</a>
|
|
59
|
+
<a href="https://pypi.org/project/pisces-cli/">
|
|
60
|
+
<img src="https://img.shields.io/pypi/pyversions/pisces-cli?color=0ea5e9&logo=python&logoColor=white" alt="Python Versions">
|
|
61
|
+
</a>
|
|
62
|
+
<a href="https://github.com/richochetclementine1315/pisces/actions/workflows/ci.yml">
|
|
63
|
+
<img src="https://github.com/richochetclementine1315/pisces/actions/workflows/ci.yml/badge.svg" alt="CI Status">
|
|
64
|
+
</a>
|
|
65
|
+
<a href="https://github.com/richochetclementine1315/pisces/blob/main/LICENSE">
|
|
66
|
+
<img src="https://img.shields.io/badge/license-MIT-22c55e?logo=opensourceinitiative&logoColor=white" alt="License: MIT">
|
|
67
|
+
</a>
|
|
68
|
+
<a href="https://github.com/richochetclementine1315/pisces/blob/main/pyproject.toml">
|
|
69
|
+
<img src="https://img.shields.io/badge/build-hatchling-f97316?logo=pypa&logoColor=white" alt="Build: Hatchling">
|
|
70
|
+
</a>
|
|
71
|
+
<img src="https://img.shields.io/badge/linter-ruff-db2777?logo=ruff&logoColor=white" alt="Linter: Ruff">
|
|
72
|
+
<img src="https://img.shields.io/badge/type--checked-mypy-2563eb?logo=python&logoColor=white" alt="Type Checked: mypy">
|
|
73
|
+
</p>
|
|
74
|
+
|
|
75
|
+
## Overview
|
|
76
|
+
|
|
77
|
+
Pisces is a Python security CLI that detects common vulnerabilities, explains
|
|
78
|
+
findings with an LLM, proposes minimal patches, validates them with your test
|
|
79
|
+
suite, and rolls them back when validation fails. Source changes remain
|
|
80
|
+
human-approved by default.
|
|
81
|
+
|
|
82
|
+
## Key Features
|
|
83
|
+
|
|
84
|
+
- AST-first and regex-fallback security scanning.
|
|
85
|
+
- Seven built-in rules for secrets, command injection, unsafe subprocesses,
|
|
86
|
+
unsafe deserialization, disabled TLS verification, code injection, and
|
|
87
|
+
dangerous filesystem operations.
|
|
88
|
+
- Excludes `.venv`, `__pycache__`, and other irrelevant directories.
|
|
89
|
+
- LLM explanations with source snippets and AST context.
|
|
90
|
+
- Human-in-the-loop patch approval.
|
|
91
|
+
- Atomic patching, checkpoints, rollback, and self-healing retries.
|
|
92
|
+
- Local repair history and a debounced watch mode.
|
|
93
|
+
- OpenAI, Anthropic, Gemini, Groq, Ollama, and LM Studio support.
|
|
94
|
+
|
|
95
|
+
## ⚙️ How it Works
|
|
96
|
+
|
|
97
|
+
<p align="center">
|
|
98
|
+
<img
|
|
99
|
+
width="450"
|
|
100
|
+
alt="How Pisces Works — Scan to History"
|
|
101
|
+
src="https://github.com/user-attachments/assets/7f421fd1-c12a-48f6-bc34-46794d67e958"
|
|
102
|
+
/>
|
|
103
|
+
</p>
|
|
104
|
+
|
|
105
|
+
## ⚙️ The Repair State Machine
|
|
106
|
+
|
|
107
|
+
<p align="center">
|
|
108
|
+
<img
|
|
109
|
+
width="450"
|
|
110
|
+
alt="How Pisces Works — Scan to History"
|
|
111
|
+
src="https://github.com/user-attachments/assets/319ae541-a87e-4f91-a860-112660c77873"
|
|
112
|
+
/>
|
|
113
|
+
</p>
|
|
114
|
+
|
|
115
|
+
## Installation
|
|
116
|
+
|
|
117
|
+
Pisces requires Python 3.10 or newer.
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
pip install pisces-cli
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Quick Usage
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
pisces init
|
|
127
|
+
pisces config
|
|
128
|
+
pisces scan .
|
|
129
|
+
pisces explain path/to/file.py:42
|
|
130
|
+
pisces fix path/to/file.py:42
|
|
131
|
+
pisces history
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Set the API key for the provider configured in `pisces.toml`, for example:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
export GROQ_API_KEY="your-key"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
On Windows PowerShell:
|
|
141
|
+
|
|
142
|
+
```powershell
|
|
143
|
+
$env:GROQ_API_KEY = "your-key"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Ollama and LM Studio use local endpoints and do not require an API key.
|
|
147
|
+
|
|
148
|
+
## Configuration
|
|
149
|
+
|
|
150
|
+
Run `pisces init` to create a project configuration:
|
|
151
|
+
|
|
152
|
+
```toml
|
|
153
|
+
[llm]
|
|
154
|
+
provider = "groq"
|
|
155
|
+
model = "llama-3.3-70b-versatile"
|
|
156
|
+
|
|
157
|
+
[repair]
|
|
158
|
+
max_attempts = 3
|
|
159
|
+
require_approval = true
|
|
160
|
+
|
|
161
|
+
[validation]
|
|
162
|
+
test_command = "pytest"
|
|
163
|
+
|
|
164
|
+
[scan]
|
|
165
|
+
exclude = [
|
|
166
|
+
".git",
|
|
167
|
+
".venv",
|
|
168
|
+
"venv",
|
|
169
|
+
"__pycache__",
|
|
170
|
+
"node_modules",
|
|
171
|
+
".pisces",
|
|
172
|
+
"dist",
|
|
173
|
+
"build",
|
|
174
|
+
]
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Do not put API keys in this file. Use environment variables instead.
|
|
178
|
+
|
|
179
|
+
## CLI Reference
|
|
180
|
+
|
|
181
|
+
| Command | Purpose |
|
|
182
|
+
|---|---|
|
|
183
|
+
| `pisces init [PATH]` | Initialize `pisces.toml` and `.pisces/`. |
|
|
184
|
+
| `pisces config [PATH] --show` | Configure or display project settings. |
|
|
185
|
+
| `pisces scan [TARGET] -o FILE -s LEVEL` | Scan a directory or Python file. |
|
|
186
|
+
| `pisces explain FILE:LINE` | Explain a cached finding with an LLM. |
|
|
187
|
+
| `pisces fix FILE:LINE` | Generate, approve, apply, and validate a patch. |
|
|
188
|
+
| `pisces watch [PATH]` | Update project context as files change. |
|
|
189
|
+
| `pisces history [PATH]` | Browse repair records and diffs. |
|
|
190
|
+
| `pisces --version` | Show the installed version. |
|
|
191
|
+
|
|
192
|
+
`pisces fix` also supports `--dry-run`, `--no-judge`, and
|
|
193
|
+
`--max-attempts N`. `pisces scan` returns exit code `1` when findings meet
|
|
194
|
+
the selected severity threshold.
|
|
195
|
+
|
|
196
|
+
## Built-in Security Rules
|
|
197
|
+
|
|
198
|
+
| Rule | ID | Severity | Detects |
|
|
199
|
+
|---|---|---|---|
|
|
200
|
+
| Hardcoded Secret | `S001` | HIGH | API keys, passwords, and tokens |
|
|
201
|
+
| Command Injection | `S002` | CRITICAL | Dynamic `shell=True` subprocess calls |
|
|
202
|
+
| Unsafe Subprocess | `S003` | HIGH | `shell=True` subprocess calls |
|
|
203
|
+
| Unsafe Deserialization | `S004` | HIGH | Unsafe pickle, marshal, or YAML loading |
|
|
204
|
+
| TLS Verify Disabled | `S005` | MEDIUM | Network calls using `verify=False` |
|
|
205
|
+
| Code Injection | `S006` | CRITICAL | Dynamic `eval()` or `exec()` |
|
|
206
|
+
| Dangerous Filesystem | `S007` | MEDIUM | Destructive operations on variable paths |
|
|
207
|
+
|
|
208
|
+
## Architecture and Workflow
|
|
209
|
+
<p align="center">
|
|
210
|
+
<img
|
|
211
|
+
width="680"
|
|
212
|
+
alt="Pisces Security Remediation Workflow"
|
|
213
|
+
src="https://github.com/user-attachments/assets/c463cbf3-73f8-4c5e-b251-f1acd6ab1b86"
|
|
214
|
+
/>
|
|
215
|
+
</p>
|
|
216
|
+
|
|
217
|
+
The workflow covers project initialization, deterministic security scanning, LLM-powered explanations and patch generation, human approval, checkpointing, test validation, rollback, and self-healing retries.
|
|
218
|
+
|
|
219
|
+
The deterministic scanner does not call an LLM. LLMs are used for explanations, patch generation, and optional patch judging. Source changes require human approval by default.
|
|
220
|
+
|
|
221
|
+
The deterministic scanner does not call an LLM. LLMs are used for explanations,
|
|
222
|
+
patch generation, and optional patch judging.
|
|
223
|
+
|
|
224
|
+
## Links
|
|
225
|
+
|
|
226
|
+
- **GitHub:** https://github.com/richochetclementine1315/pisces
|
|
227
|
+
- **Issues:** https://github.com/richochetclementine1315/pisces/issues
|
|
228
|
+
- **PyPI:** https://pypi.org/project/pisces-cli/
|
|
229
|
+
|
|
230
|
+
## License
|
|
231
|
+
|
|
232
|
+
MIT © [Mrinmoy Matilal](https://github.com/richochetclementine1315/pisces)
|
|
@@ -11,6 +11,26 @@
|
|
|
11
11
|
<b>AI-Assisted · Self-Healing · Human-Governed Python Security Remediation Patcher</b>
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="https://pypi.org/project/pisces-cli/">
|
|
16
|
+
<img src="https://img.shields.io/pypi/v/pisces-cli?color=7c3aed&logo=pypi&logoColor=white&label=PyPI" alt="PyPI Version">
|
|
17
|
+
</a>
|
|
18
|
+
<a href="https://pypi.org/project/pisces-cli/">
|
|
19
|
+
<img src="https://img.shields.io/pypi/pyversions/pisces-cli?color=0ea5e9&logo=python&logoColor=white" alt="Python Versions">
|
|
20
|
+
</a>
|
|
21
|
+
<a href="https://github.com/richochetclementine1315/pisces/actions/workflows/ci.yml">
|
|
22
|
+
<img src="https://github.com/richochetclementine1315/pisces/actions/workflows/ci.yml/badge.svg" alt="CI Status">
|
|
23
|
+
</a>
|
|
24
|
+
<a href="https://github.com/richochetclementine1315/pisces/blob/main/LICENSE">
|
|
25
|
+
<img src="https://img.shields.io/badge/license-MIT-22c55e?logo=opensourceinitiative&logoColor=white" alt="License: MIT">
|
|
26
|
+
</a>
|
|
27
|
+
<a href="https://github.com/richochetclementine1315/pisces/blob/main/pyproject.toml">
|
|
28
|
+
<img src="https://img.shields.io/badge/build-hatchling-f97316?logo=pypa&logoColor=white" alt="Build: Hatchling">
|
|
29
|
+
</a>
|
|
30
|
+
<img src="https://img.shields.io/badge/linter-ruff-db2777?logo=ruff&logoColor=white" alt="Linter: Ruff">
|
|
31
|
+
<img src="https://img.shields.io/badge/type--checked-mypy-2563eb?logo=python&logoColor=white" alt="Type Checked: mypy">
|
|
32
|
+
</p>
|
|
33
|
+
|
|
14
34
|
## Overview
|
|
15
35
|
|
|
16
36
|
Pisces is a Python security CLI that detects common vulnerabilities, explains
|
|
@@ -24,13 +44,33 @@ human-approved by default.
|
|
|
24
44
|
- Seven built-in rules for secrets, command injection, unsafe subprocesses,
|
|
25
45
|
unsafe deserialization, disabled TLS verification, code injection, and
|
|
26
46
|
dangerous filesystem operations.
|
|
27
|
-
- Excludes `.venv`,
|
|
47
|
+
- Excludes `.venv`, `__pycache__`, and other irrelevant directories.
|
|
28
48
|
- LLM explanations with source snippets and AST context.
|
|
29
49
|
- Human-in-the-loop patch approval.
|
|
30
50
|
- Atomic patching, checkpoints, rollback, and self-healing retries.
|
|
31
51
|
- Local repair history and a debounced watch mode.
|
|
32
52
|
- OpenAI, Anthropic, Gemini, Groq, Ollama, and LM Studio support.
|
|
33
53
|
|
|
54
|
+
## ⚙️ How it Works
|
|
55
|
+
|
|
56
|
+
<p align="center">
|
|
57
|
+
<img
|
|
58
|
+
width="450"
|
|
59
|
+
alt="How Pisces Works — Scan to History"
|
|
60
|
+
src="https://github.com/user-attachments/assets/7f421fd1-c12a-48f6-bc34-46794d67e958"
|
|
61
|
+
/>
|
|
62
|
+
</p>
|
|
63
|
+
|
|
64
|
+
## ⚙️ The Repair State Machine
|
|
65
|
+
|
|
66
|
+
<p align="center">
|
|
67
|
+
<img
|
|
68
|
+
width="450"
|
|
69
|
+
alt="How Pisces Works — Scan to History"
|
|
70
|
+
src="https://github.com/user-attachments/assets/319ae541-a87e-4f91-a860-112660c77873"
|
|
71
|
+
/>
|
|
72
|
+
</p>
|
|
73
|
+
|
|
34
74
|
## Installation
|
|
35
75
|
|
|
36
76
|
Pisces requires Python 3.10 or newer.
|
|
@@ -125,24 +165,17 @@ the selected severity threshold.
|
|
|
125
165
|
| Dangerous Filesystem | `S007` | MEDIUM | Destructive operations on variable paths |
|
|
126
166
|
|
|
127
167
|
## Architecture and Workflow
|
|
168
|
+
<p align="center">
|
|
169
|
+
<img
|
|
170
|
+
width="680"
|
|
171
|
+
alt="Pisces Security Remediation Workflow"
|
|
172
|
+
src="https://github.com/user-attachments/assets/c463cbf3-73f8-4c5e-b251-f1acd6ab1b86"
|
|
173
|
+
/>
|
|
174
|
+
</p>
|
|
128
175
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
B --> C[Exclude .venv* and configured paths]
|
|
133
|
-
C --> D[AST plus regex scanner]
|
|
134
|
-
D --> E[Findings cache]
|
|
135
|
-
E --> F[pisces explain or pisces fix]
|
|
136
|
-
F --> G[LLM context and response]
|
|
137
|
-
G --> H{Fix approved?}
|
|
138
|
-
H -- No --> I[No source change]
|
|
139
|
-
H -- Yes --> J[Checkpoint and atomically apply patch]
|
|
140
|
-
J --> K[Run configured tests]
|
|
141
|
-
K --> L{Pass?}
|
|
142
|
-
L -- Yes --> M[Repair history]
|
|
143
|
-
L -- No --> N[Rollback and retry]
|
|
144
|
-
N --> G
|
|
145
|
-
```
|
|
176
|
+
The workflow covers project initialization, deterministic security scanning, LLM-powered explanations and patch generation, human approval, checkpointing, test validation, rollback, and self-healing retries.
|
|
177
|
+
|
|
178
|
+
The deterministic scanner does not call an LLM. LLMs are used for explanations, patch generation, and optional patch judging. Source changes require human approval by default.
|
|
146
179
|
|
|
147
180
|
The deterministic scanner does not call an LLM. LLMs are used for explanations,
|
|
148
181
|
patch generation, and optional patch judging.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# Can be run multiple times(idempotent).abs
|
|
4
4
|
# creates pisces.toml and the .pisces/ state directory
|
|
5
5
|
# NEVER destructively overwrites without --force
|
|
6
|
-
# Adds
|
|
6
|
+
# Adds Pisces-generated files to .gitignore.
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
import json
|
|
@@ -150,10 +150,10 @@ def _create_dir(path: Path) -> None:
|
|
|
150
150
|
return False
|
|
151
151
|
|
|
152
152
|
|
|
153
|
-
def _init_context_json(path: Path, project_root: Path, *, force: bool) ->
|
|
153
|
+
def _init_context_json(path: Path, project_root: Path, *, force: bool) -> bool:
|
|
154
154
|
if path.exists() and not force:
|
|
155
155
|
print_step_ok("context.json already exists - skipping")
|
|
156
|
-
return
|
|
156
|
+
return True
|
|
157
157
|
|
|
158
158
|
print_step_running("Writing context.json ...")
|
|
159
159
|
try:
|
|
@@ -162,32 +162,46 @@ def _init_context_json(path: Path, project_root: Path, *, force: bool) -> None:
|
|
|
162
162
|
encoding="utf-8",
|
|
163
163
|
)
|
|
164
164
|
print_step_ok("context.json initialized")
|
|
165
|
+
return True
|
|
165
166
|
except OSError as e:
|
|
166
167
|
print_step_fail(f"Could not write context.json: {e}")
|
|
168
|
+
return False
|
|
167
169
|
|
|
168
170
|
|
|
169
171
|
def _update_gitignore(project_root: Path) -> None:
|
|
170
|
-
"""Ensure
|
|
172
|
+
"""Ensure Pisces-generated files are listed in .gitignore."""
|
|
171
173
|
gitignore = project_root / ".gitignore"
|
|
172
|
-
|
|
174
|
+
entries = (".pisces/", "pisces.toml")
|
|
173
175
|
|
|
174
176
|
if not gitignore.exists():
|
|
175
|
-
print_step_running("No .
|
|
177
|
+
print_step_running("No .gitignore found - creating one ...")
|
|
176
178
|
try:
|
|
177
|
-
gitignore.write_text(
|
|
178
|
-
|
|
179
|
+
gitignore.write_text(
|
|
180
|
+
"# pisces generated files\n"
|
|
181
|
+
+ "".join(f"{entry}\n" for entry in entries),
|
|
182
|
+
encoding="utf-8",
|
|
183
|
+
)
|
|
184
|
+
print_step_ok(".gitignore created with Pisces entries")
|
|
179
185
|
except OSError as e:
|
|
180
|
-
print_warning(f"
|
|
186
|
+
print_warning(f"Could not create .gitignore: {e}")
|
|
187
|
+
return
|
|
188
|
+
|
|
189
|
+
try:
|
|
190
|
+
content = gitignore.read_text(encoding="utf-8")
|
|
191
|
+
except OSError as e:
|
|
192
|
+
print_warning(f"Could not read .gitignore: {e}")
|
|
181
193
|
return
|
|
182
194
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
195
|
+
existing_entries = {line.strip() for line in content.splitlines()}
|
|
196
|
+
missing_entries = [entry for entry in entries if entry not in existing_entries]
|
|
197
|
+
if not missing_entries:
|
|
198
|
+
print_step_ok(".gitignore already contains Pisces entries - skipping")
|
|
186
199
|
return
|
|
187
200
|
|
|
188
201
|
try:
|
|
189
202
|
with gitignore.open("a", encoding="utf-8") as f:
|
|
190
|
-
f.write(
|
|
191
|
-
|
|
203
|
+
f.write("\n# pisces generated files\n")
|
|
204
|
+
f.writelines(f"{entry}\n" for entry in missing_entries)
|
|
205
|
+
print_step_ok("Added Pisces entries to .gitignore")
|
|
192
206
|
except OSError as e:
|
|
193
207
|
print_warning(f"Could not update .gitignore: {e}")
|
|
@@ -61,7 +61,7 @@ _BANNER_LINES = [
|
|
|
61
61
|
(" ╚═╝ ╚═╝ ╚══════╝ ╚═════╝ ╚══════╝ ╚══════╝ ", "bold blue"),
|
|
62
62
|
]
|
|
63
63
|
_TAGLINE = " AI-assisted Python Security · Detect · Patch · Validate · Self-Heal"
|
|
64
|
-
_VERSION_LINE = " v0.1.
|
|
64
|
+
_VERSION_LINE = " v0.1.2 · MIT License · pip install pisces"
|
|
65
65
|
|
|
66
66
|
|
|
67
67
|
def print_banner() -> None:
|
|
@@ -4,9 +4,9 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pisces-cli"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.2"
|
|
8
8
|
description = "AI-assisted,self healing human-governed Python security remediation patcher"
|
|
9
|
-
readme = "
|
|
9
|
+
readme = "PYPI_README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
11
11
|
requires-python = ">=3.10"
|
|
12
12
|
authors = [
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from pisces.init_cmd import run_init
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_run_init_adds_generated_files_to_new_gitignore(tmp_path: Path) -> None:
|
|
7
|
+
assert run_init(tmp_path) == 0
|
|
8
|
+
|
|
9
|
+
gitignore = (tmp_path / ".gitignore").read_text(encoding="utf-8")
|
|
10
|
+
assert ".pisces/" in gitignore.splitlines()
|
|
11
|
+
assert "pisces.toml" in gitignore.splitlines()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_run_init_adds_pisces_toml_to_existing_gitignore(tmp_path: Path) -> None:
|
|
15
|
+
(tmp_path / ".gitignore").write_text(".venv/\n", encoding="utf-8")
|
|
16
|
+
|
|
17
|
+
assert run_init(tmp_path) == 0
|
|
18
|
+
|
|
19
|
+
lines = (tmp_path / ".gitignore").read_text(encoding="utf-8").splitlines()
|
|
20
|
+
assert lines.count(".pisces/") == 1
|
|
21
|
+
assert lines.count("pisces.toml") == 1
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_run_init_does_not_duplicate_gitignore_entries(tmp_path: Path) -> None:
|
|
25
|
+
(tmp_path / ".gitignore").write_text(
|
|
26
|
+
"# pisces generated files\n.pisces/\npisces.toml\n",
|
|
27
|
+
encoding="utf-8",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
assert run_init(tmp_path) == 0
|
|
31
|
+
|
|
32
|
+
content = (tmp_path / ".gitignore").read_text(encoding="utf-8")
|
|
33
|
+
assert content.count(".pisces/") == 1
|
|
34
|
+
assert content.count("pisces.toml") == 1
|
pisces_cli-0.1.0/PKG-INFO
DELETED
|
@@ -1,448 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.5
|
|
2
|
-
Name: pisces-cli
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: AI-assisted,self healing human-governed Python security remediation patcher
|
|
5
|
-
Project-URL: Homepage, https://github.com/richochetclementine1315/pisces
|
|
6
|
-
Project-URL: Repository, https://github.com/richochetclementine1315/pisces
|
|
7
|
-
Project-URL: Issues, https://github.com/richochetclementine1315/pisces/issues
|
|
8
|
-
Author-email: Mrinmoy Matilal <mrinmoymatilal1315@gmail.com>
|
|
9
|
-
License: MIT
|
|
10
|
-
License-File: LICENSE
|
|
11
|
-
Keywords: ai,cli,llm,patcher,python,scanner,security,static-analysis,vulnerability
|
|
12
|
-
Classifier: Development Status :: 3 - Alpha
|
|
13
|
-
Classifier: Environment :: Console
|
|
14
|
-
Classifier: Intended Audience :: Developers
|
|
15
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
-
Classifier: Operating System :: OS Independent
|
|
17
|
-
Classifier: Programming Language :: Python :: 3
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
-
Classifier: Topic :: Security
|
|
22
|
-
Classifier: Topic :: Software Development :: Quality Assurance
|
|
23
|
-
Requires-Python: >=3.10
|
|
24
|
-
Requires-Dist: anthropic>=0.28.0
|
|
25
|
-
Requires-Dist: bandit>=1.7.0
|
|
26
|
-
Requires-Dist: google-generativeai>=0.7.0
|
|
27
|
-
Requires-Dist: groq>=0.9.0
|
|
28
|
-
Requires-Dist: httpx>=0.27.0
|
|
29
|
-
Requires-Dist: jsonschema>=4.22.0
|
|
30
|
-
Requires-Dist: openai>=1.30.0
|
|
31
|
-
Requires-Dist: rich>=13.7.0
|
|
32
|
-
Requires-Dist: tomli>=2.0.0; python_version < '3.11'
|
|
33
|
-
Requires-Dist: typer>=0.12.0
|
|
34
|
-
Requires-Dist: watchdog>=4.0.0
|
|
35
|
-
Provides-Extra: dev
|
|
36
|
-
Requires-Dist: mypy>=1.10.0; extra == 'dev'
|
|
37
|
-
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
|
|
38
|
-
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
39
|
-
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
40
|
-
Description-Content-Type: text/markdown
|
|
41
|
-
|
|
42
|
-
<p align="center">
|
|
43
|
-
<img src="https://github.com/user-attachments/assets/66723bfc-b15b-44bb-8dfa-cc74ff298ade"
|
|
44
|
-
width="280"
|
|
45
|
-
height="100"
|
|
46
|
-
alt="Pisces Banner">
|
|
47
|
-
</p>
|
|
48
|
-
|
|
49
|
-
<h1 align="center">PISCES</h1>
|
|
50
|
-
|
|
51
|
-
<p align="center">
|
|
52
|
-
<b>AI-Assisted · Self-Healing · Human-Governed Python Security Remediation Patcher</b>
|
|
53
|
-
</p>
|
|
54
|
-
|
|
55
|
-
<p align="center">
|
|
56
|
-
<a href="https://pypi.org/project/pisces-cli/">
|
|
57
|
-
<img src="https://img.shields.io/pypi/v/pisces-cli?color=7c3aed&logo=pypi&logoColor=white&label=PyPI" alt="PyPI Version">
|
|
58
|
-
</a>
|
|
59
|
-
<a href="https://pypi.org/project/pisces-cli/">
|
|
60
|
-
<img src="https://img.shields.io/pypi/pyversions/pisces-cli?color=0ea5e9&logo=python&logoColor=white" alt="Python Versions">
|
|
61
|
-
</a>
|
|
62
|
-
<a href="https://github.com/richochetclementine1315/pisces/actions/workflows/ci.yml">
|
|
63
|
-
<img src="https://github.com/richochetclementine1315/pisces/actions/workflows/ci.yml/badge.svg" alt="CI Status">
|
|
64
|
-
</a>
|
|
65
|
-
<a href="https://github.com/richochetclementine1315/pisces/blob/main/LICENSE">
|
|
66
|
-
<img src="https://img.shields.io/badge/license-MIT-22c55e?logo=opensourceinitiative&logoColor=white" alt="License: MIT">
|
|
67
|
-
</a>
|
|
68
|
-
<a href="https://github.com/richochetclementine1315/pisces/blob/main/pyproject.toml">
|
|
69
|
-
<img src="https://img.shields.io/badge/build-hatchling-f97316?logo=pypa&logoColor=white" alt="Build: Hatchling">
|
|
70
|
-
</a>
|
|
71
|
-
<img src="https://img.shields.io/badge/linter-ruff-db2777?logo=ruff&logoColor=white" alt="Linter: Ruff">
|
|
72
|
-
<img src="https://img.shields.io/badge/type--checked-mypy-2563eb?logo=python&logoColor=white" alt="Type Checked: mypy">
|
|
73
|
-
</p>
|
|
74
|
-
|
|
75
|
-
<p align="center">
|
|
76
|
-
<a href="#-what-is-pisces">What is Pisces?</a> •
|
|
77
|
-
<a href="#-how-it-works">How it Works</a> •
|
|
78
|
-
<a href="#-installation">Installation</a> •
|
|
79
|
-
<a href="#-quick-start">Quick Start</a> •
|
|
80
|
-
<a href="#-commands">Commands</a> •
|
|
81
|
-
<a href="#-configuration">Configuration</a> •
|
|
82
|
-
<a href="#-supported-providers">LLM Providers</a> •
|
|
83
|
-
<a href="#-security-rules">Security Rules</a> •
|
|
84
|
-
<a href="#-contributing">Contributing</a>
|
|
85
|
-
</p>
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
## 🐟 What is Pisces?
|
|
90
|
-
|
|
91
|
-
**Pisces** is an AI-powered, self-healing security CLI for Python codebases. It doesn't just *find* vulnerabilities — it *fixes* them, validates the fix against your test suite, and rolls back automatically if anything breaks.
|
|
92
|
-
|
|
93
|
-
At its core, Pisces is a **three-stage pipeline**:
|
|
94
|
-
|
|
95
|
-
| Stage | What happens |
|
|
96
|
-
|---|---|
|
|
97
|
-
| 🔍 **Detect** | 7 built-in AST + regex security rules scan your code |
|
|
98
|
-
| 🤖 **Remediate** | An LLM generates a minimal, targeted patch |
|
|
99
|
-
| ✅ **Validate** | Your own test suite verifies the fix works |
|
|
100
|
-
|
|
101
|
-
The entire process is governed by a **Human-in-the-Loop (HITL)** approval gate — Pisces asks *you* before touching any source file.
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## ⚙️ How it Works
|
|
106
|
-
|
|
107
|
-
```
|
|
108
|
-
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
|
109
|
-
│ pisces scan │ ──▶ │pisces explain│ ──▶ │ pisces fix │ ──▶ │pisces history│
|
|
110
|
-
│ │ │ │ │ │ │ │
|
|
111
|
-
│ Runs 7 rules │ │ LLM analyses │ │ LLM patches │ │ Audit trail │
|
|
112
|
-
│ on .py files │ │ the finding │ │ Judge reviews│ │ of all fixes │
|
|
113
|
-
│ │ │ with full │ │ You approve │ │ │
|
|
114
|
-
│ Caches to │ │ attack │ │ Tests run │ │ Full diff │
|
|
115
|
-
│ .pisces/cache│ │ scenario │ │ Rollback if │ │ Judge scores │
|
|
116
|
-
└──────────────┘ └──────────────┘ │ tests fail │ └──────────────┘
|
|
117
|
-
└──────────────┘
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### The Repair State Machine
|
|
121
|
-
|
|
122
|
-
```
|
|
123
|
-
DETECTED ──▶ PROPOSED ──▶ JUDGED ──▶ AWAITING_APPROVAL
|
|
124
|
-
│
|
|
125
|
-
┌─────────────┴──────────────┐
|
|
126
|
-
▼ ▼
|
|
127
|
-
APPROVED REJECTED ✗
|
|
128
|
-
│
|
|
129
|
-
CHECKPOINTED
|
|
130
|
-
│
|
|
131
|
-
APPLIED
|
|
132
|
-
│
|
|
133
|
-
VALIDATING
|
|
134
|
-
┌────┴────┐
|
|
135
|
-
▼ ▼
|
|
136
|
-
SUCCEEDED FAILED ──▶ HEALING ──▶ PROPOSED (retry)
|
|
137
|
-
✓ │
|
|
138
|
-
ROLLED_BACK ✗
|
|
139
|
-
(all attempts exhausted)
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### Atomicity Guarantee
|
|
143
|
-
|
|
144
|
-
Pisces **never writes directly to your source file**. Every patch goes through:
|
|
145
|
-
|
|
146
|
-
1. 📋 **Checkpoint** — `original.py` saved to `.pisces/history/<id>/`
|
|
147
|
-
2. ✏️ **Write** — patch written to `file.py.tmp`
|
|
148
|
-
3. 🔄 **Rename** — `.tmp → file.py` (atomic on all OSes)
|
|
149
|
-
4. ↩️ **Rollback** — on any failure, `original.py` is restored
|
|
150
|
-
|
|
151
|
-
### Architecture and Workflow
|
|
152
|
-
|
|
153
|
-
```mermaid
|
|
154
|
-
flowchart TD
|
|
155
|
-
A[Developer runs pisces init] --> B[pisces.toml and .pisces state]
|
|
156
|
-
B --> C[pisces scan TARGET]
|
|
157
|
-
C --> D[Discover project .py files]
|
|
158
|
-
D --> E[Exclude .venv* and configured directories]
|
|
159
|
-
E --> F[AST and regex security rules]
|
|
160
|
-
F --> G[Findings cache]
|
|
161
|
-
G --> H[pisces explain FILE:LINE]
|
|
162
|
-
H --> I[Source snippet and AST context]
|
|
163
|
-
I --> J[LLM explanation]
|
|
164
|
-
G --> K[pisces fix FILE:LINE]
|
|
165
|
-
K --> L[Generate minimal patch]
|
|
166
|
-
L --> M[LLM judge]
|
|
167
|
-
M --> N{Human approves?}
|
|
168
|
-
N -- No --> O[Stop without changing source]
|
|
169
|
-
N -- Yes --> P[Checkpoint original file]
|
|
170
|
-
P --> Q[Apply atomic patch]
|
|
171
|
-
Q --> R[Run configured test command]
|
|
172
|
-
R --> S{Tests pass?}
|
|
173
|
-
S -- Yes --> T[Save repair history]
|
|
174
|
-
S -- No --> U[Rollback and retry healing loop]
|
|
175
|
-
U --> L
|
|
176
|
-
B --> V[pisces watch]
|
|
177
|
-
V --> W[Debounced context updates]
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
The deterministic scanner does not call an LLM. LLMs are used only for
|
|
181
|
-
explanations, patch generation, and optional patch judging. API credentials
|
|
182
|
-
are read from environment variables and are never stored in `pisces.toml`.
|
|
183
|
-
|
|
184
|
-
---
|
|
185
|
-
|
|
186
|
-
## 🚀 Installation
|
|
187
|
-
|
|
188
|
-
### From PyPI (recommended)
|
|
189
|
-
|
|
190
|
-
```bash
|
|
191
|
-
pip install pisces-cli
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
### From Source
|
|
195
|
-
|
|
196
|
-
```bash
|
|
197
|
-
git clone https://github.com/richochetclementine1315/pisces.git
|
|
198
|
-
cd pisces
|
|
199
|
-
pip install -e ".[dev]"
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
### Requirements
|
|
203
|
-
|
|
204
|
-
- **Python** ≥ 3.10
|
|
205
|
-
- An API key for your chosen LLM provider (see [Supported Providers](#-supported-providers))
|
|
206
|
-
|
|
207
|
-
---
|
|
208
|
-
|
|
209
|
-
## ⚡ Quick Start
|
|
210
|
-
|
|
211
|
-
```bash
|
|
212
|
-
# 1. Initialize Pisces in your project
|
|
213
|
-
pisces init
|
|
214
|
-
|
|
215
|
-
# 2. Set your LLM provider API key (example: Groq)
|
|
216
|
-
export GROQ_API_KEY=your_key_here
|
|
217
|
-
|
|
218
|
-
# 3. Configure provider & model
|
|
219
|
-
pisces config
|
|
220
|
-
|
|
221
|
-
# 4. Scan for vulnerabilities
|
|
222
|
-
pisces scan .
|
|
223
|
-
|
|
224
|
-
# 5. Get an AI explanation of a finding
|
|
225
|
-
pisces explain auth.py:42
|
|
226
|
-
|
|
227
|
-
# 6. Apply a self-healing patch (with HITL approval)
|
|
228
|
-
pisces fix auth.py:42
|
|
229
|
-
|
|
230
|
-
# 7. Review your repair history
|
|
231
|
-
pisces history
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
---
|
|
235
|
-
|
|
236
|
-
## 📟 Commands
|
|
237
|
-
|
|
238
|
-
### `pisces init` — Initialize Project
|
|
239
|
-
|
|
240
|
-
```bash
|
|
241
|
-
pisces init [PATH] [--force / -f]
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
Creates `pisces.toml`, `.pisces/` state directory, and updates `.gitignore`.
|
|
245
|
-
|
|
246
|
-
| Option | Short | Default | Description |
|
|
247
|
-
|---|---|---|---|
|
|
248
|
-
| `PATH` | | `.` | Project root to initialize |
|
|
249
|
-
| `--force` | `-f` | `False` | Overwrite existing `pisces.toml` |
|
|
250
|
-
|
|
251
|
-
---
|
|
252
|
-
|
|
253
|
-
### `pisces config` — Configuration Wizard
|
|
254
|
-
|
|
255
|
-
```bash
|
|
256
|
-
pisces config [PATH] [--show / -s]
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
Interactive wizard that configures provider, model, HITL, and test command.
|
|
260
|
-
|
|
261
|
-
| Option | Short | Default | Description |
|
|
262
|
-
|---|---|---|---|
|
|
263
|
-
| `PATH` | | `.` | Project root |
|
|
264
|
-
| `--show` | `-s` | `False` | Print current config table and exit |
|
|
265
|
-
|
|
266
|
-
---
|
|
267
|
-
|
|
268
|
-
### `pisces scan` — Security Scanner
|
|
269
|
-
|
|
270
|
-
```bash
|
|
271
|
-
pisces scan [TARGET] [--output FILE] [--min-severity LEVEL]
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
Scans Python files with 7 built-in security rules. Caches results for `explain` and `fix`.
|
|
275
|
-
|
|
276
|
-
| Option | Short | Default | Description |
|
|
277
|
-
|---|---|---|---|
|
|
278
|
-
| `TARGET` | | `.` | Directory or `.py` file |
|
|
279
|
-
| `--output FILE` | `-o` | `None` | Save findings as JSON |
|
|
280
|
-
| `--min-severity` | `-s` | `LOW` | `CRITICAL` / `HIGH` / `MEDIUM` / `LOW` / `INFO` |
|
|
281
|
-
|
|
282
|
-
**Exit code:** `1` if findings exist at/above threshold, `0` if clean — ideal for CI.
|
|
283
|
-
|
|
284
|
-
---
|
|
285
|
-
|
|
286
|
-
### `pisces explain` — AI Vulnerability Analysis
|
|
287
|
-
|
|
288
|
-
```bash
|
|
289
|
-
pisces explain <file:line>
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
Sends the finding + ±20 lines of source + AST context to the LLM. Renders a **6-section structured report**:
|
|
293
|
-
|
|
294
|
-
| Section | Content |
|
|
295
|
-
|---|---|
|
|
296
|
-
| 📋 Executive Summary | One-line verdict |
|
|
297
|
-
| 🔍 Vulnerability Explained | Technical deep-dive |
|
|
298
|
-
| ⚔️ Attack Scenario | Step-by-step exploitation |
|
|
299
|
-
| 🎯 Root Cause | Exact line + mistake |
|
|
300
|
-
| 🛠️ Recommended Fix | Corrected code with comments |
|
|
301
|
-
| 📚 References | CWE, OWASP, CVE links |
|
|
302
|
-
|
|
303
|
-
---
|
|
304
|
-
|
|
305
|
-
### `pisces fix` — Self-Healing Repair
|
|
306
|
-
|
|
307
|
-
```bash
|
|
308
|
-
pisces fix <file:line> [OPTIONS]
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
The full repair pipeline: generate → judge → approve → patch → test → heal.
|
|
312
|
-
|
|
313
|
-
| Option | Short | Default | Description |
|
|
314
|
-
|---|---|---|---|
|
|
315
|
-
| `--dry-run` | | `False` | Show patch without modifying files |
|
|
316
|
-
| `--no-judge` | | `False` | Skip adversarial LLM judge |
|
|
317
|
-
| `--max-attempts N` | `-m` | from config | Max self-healing retries |
|
|
318
|
-
|
|
319
|
-
---
|
|
320
|
-
|
|
321
|
-
### `pisces watch` — Live Context Watcher
|
|
322
|
-
|
|
323
|
-
```bash
|
|
324
|
-
pisces watch [PATH]
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
Watches `.py` files with 0.8s debouncing. Auto-updates `context.json` on every save. Press `Ctrl+C` to stop.
|
|
328
|
-
|
|
329
|
-
---
|
|
330
|
-
|
|
331
|
-
### `pisces history` — Repair Audit Log
|
|
332
|
-
|
|
333
|
-
```bash
|
|
334
|
-
pisces history [PATH] [--detail ID] [--limit N]
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
| Option | Short | Default | Description |
|
|
338
|
-
|---|---|---|---|
|
|
339
|
-
| `--detail REPAIR_ID` | `-d` | `None` | Full detail + diff for one repair |
|
|
340
|
-
| `--limit N` | `-n` | `20` | Records to show in list view |
|
|
341
|
-
|
|
342
|
-
---
|
|
343
|
-
|
|
344
|
-
## 🔧 Configuration
|
|
345
|
-
|
|
346
|
-
**`pisces.toml`** (project root — never put API keys here):
|
|
347
|
-
|
|
348
|
-
```toml
|
|
349
|
-
[llm]
|
|
350
|
-
provider = "groq" # openai | anthropic | gemini | groq | ollama | lmstudio
|
|
351
|
-
model = "llama-3.3-70b-versatile" # any model your provider supports
|
|
352
|
-
|
|
353
|
-
[repair]
|
|
354
|
-
max_attempts = 3 # self-healing retry limit
|
|
355
|
-
require_approval = true # HITL — always ask before patching
|
|
356
|
-
|
|
357
|
-
[validation]
|
|
358
|
-
test_command = "pytest" # command to validate patches
|
|
359
|
-
|
|
360
|
-
[scan]
|
|
361
|
-
exclude = [".git", ".venv", "__pycache__", "node_modules", ".pisces", "dist", "build"]
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
---
|
|
365
|
-
|
|
366
|
-
## 🤖 Supported Providers
|
|
367
|
-
|
|
368
|
-
| Provider | Env Var | Default Model |
|
|
369
|
-
|---|---|---|
|
|
370
|
-
| `openai` | `OPENAI_API_KEY` | `gpt-4o-mini` |
|
|
371
|
-
| `anthropic` | `ANTHROPIC_API_KEY` | `claude-3-5-haiku-20241022` |
|
|
372
|
-
| `gemini` | `GOOGLE_API_KEY` or `GEMINI_API_KEY` | `gemini-2.0-flash` |
|
|
373
|
-
| `groq` | `GROQ_API_KEY` | `llama-3.3-70b-versatile` |
|
|
374
|
-
| `ollama` | *(none — local)* | `llama3.2` |
|
|
375
|
-
| `lmstudio` | *(none — local)* | `local-model` |
|
|
376
|
-
|
|
377
|
-
---
|
|
378
|
-
|
|
379
|
-
## 🛡️ Security Rules
|
|
380
|
-
|
|
381
|
-
| Rule | ID | Severity | What it Detects |
|
|
382
|
-
|---|---|---|---|
|
|
383
|
-
| Hardcoded Secret | `S001` | HIGH | API keys, passwords, tokens in source code |
|
|
384
|
-
| Command Injection | `S002` | CRITICAL | `subprocess` with f-strings/vars + `shell=True` |
|
|
385
|
-
| Unsafe Subprocess | `S003` | HIGH | `shell=True` even with static strings |
|
|
386
|
-
| Unsafe Deserialization | `S004` | HIGH | `pickle.load`, `yaml.load` without `SafeLoader` |
|
|
387
|
-
| TLS Verify Disabled | `S005` | HIGH | `requests.get(..., verify=False)` |
|
|
388
|
-
| Code Injection | `S006` | CRITICAL | `eval(var)`, `exec(var)` with user input |
|
|
389
|
-
| Dangerous Filesystem | `S007` | MEDIUM | `shutil.rmtree(variable_path)` |
|
|
390
|
-
|
|
391
|
-
---
|
|
392
|
-
|
|
393
|
-
## 🗂️ Project Layout
|
|
394
|
-
|
|
395
|
-
```
|
|
396
|
-
Pisces/
|
|
397
|
-
├── pisces/
|
|
398
|
-
│ ├── cli.py # Typer CLI entrypoint — all commands
|
|
399
|
-
│ ├── models.py # Shared dataclasses (Finding, JudgeResult, RepairState…)
|
|
400
|
-
│ ├── scanner.py # 7 security rules (AST + regex)
|
|
401
|
-
│ ├── scan_cmd.py # `pisces scan` implementation
|
|
402
|
-
│ ├── explain_cmd.py # `pisces explain` implementation
|
|
403
|
-
│ ├── fix_cmd.py # `pisces fix` state machine
|
|
404
|
-
│ ├── patch_engine.py # Atomic patch apply, checkpoint, rollback
|
|
405
|
-
│ ├── judge.py # Adversarial LLM judge
|
|
406
|
-
│ ├── history_cmd.py # `pisces history` implementation
|
|
407
|
-
│ ├── watcher.py # `pisces watch` — watchdog integration
|
|
408
|
-
│ ├── config_cmd.py # `pisces config` wizard
|
|
409
|
-
│ ├── config_manager.py # pisces.toml loader/writer
|
|
410
|
-
│ ├── context_manager.py# context.json AST index
|
|
411
|
-
│ ├── llm_client.py # Multi-provider LLM client
|
|
412
|
-
│ ├── ast_visitor.py # AST walker for file intelligence
|
|
413
|
-
│ └── tui.py # Rich TUI primitives
|
|
414
|
-
├── tests/
|
|
415
|
-
│ ├── conftest.py
|
|
416
|
-
│ ├── test_scanner.py
|
|
417
|
-
│ ├── test_patch_engine.py
|
|
418
|
-
│ ├── test_models.py
|
|
419
|
-
│ ├── test_config_manager.py
|
|
420
|
-
│ └── test_context_manager.py
|
|
421
|
-
├── pyproject.toml
|
|
422
|
-
├── pisces.toml
|
|
423
|
-
└── README.md
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
---
|
|
427
|
-
|
|
428
|
-
## 🤝 Contributing
|
|
429
|
-
|
|
430
|
-
Contributions are welcome! Please open an issue before submitting a PR.
|
|
431
|
-
|
|
432
|
-
```bash
|
|
433
|
-
git clone https://github.com/richochetclementine1315/pisces.git
|
|
434
|
-
cd pisces
|
|
435
|
-
pip install -e ".[dev]"
|
|
436
|
-
pytest tests/ -v
|
|
437
|
-
ruff check pisces/ tests/
|
|
438
|
-
```
|
|
439
|
-
|
|
440
|
-
---
|
|
441
|
-
|
|
442
|
-
## 📄 License
|
|
443
|
-
|
|
444
|
-
MIT © [Mrinmoy Matilal](https://github.com/richochetclementine1315)
|
|
445
|
-
|
|
446
|
-
---
|
|
447
|
-
|
|
448
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|