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.
Files changed (40) hide show
  1. pisces_cli-0.1.2/PKG-INFO +232 -0
  2. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/PYPI_README.md +51 -18
  3. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/__init__.py +1 -1
  4. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/init_cmd.py +28 -14
  5. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/tui.py +1 -1
  6. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pyproject.toml +2 -2
  7. pisces_cli-0.1.2/tests/test_init_cmd.py +34 -0
  8. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/uv.lock +1 -1
  9. pisces_cli-0.1.0/PKG-INFO +0 -448
  10. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/.github/workflows/ci.yml +0 -0
  11. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/.github/workflows/pypi-publish.yml +0 -0
  12. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/.gitignore +0 -0
  13. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/.python-version +0 -0
  14. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/CONTRIBUTION.md +0 -0
  15. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/LICENSE +0 -0
  16. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/README.md +0 -0
  17. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/__main__.py +0 -0
  18. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/ast_visitor.py +0 -0
  19. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/cli.py +0 -0
  20. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/config_cmd.py +0 -0
  21. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/config_manager.py +0 -0
  22. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/context_manager.py +0 -0
  23. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/explain_cmd.py +0 -0
  24. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/fix_cmd.py +0 -0
  25. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/history_cmd.py +0 -0
  26. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/judge.py +0 -0
  27. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/llm_client.py +0 -0
  28. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/models.py +0 -0
  29. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/patch_engine.py +0 -0
  30. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/scan_cmd.py +0 -0
  31. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/scanner.py +0 -0
  32. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/pisces/watcher.py +0 -0
  33. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/requirements.txt +0 -0
  34. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/tests/__init__.py +0 -0
  35. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/tests/conftest.py +0 -0
  36. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/tests/test_config_manager.py +0 -0
  37. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/tests/test_context_manager.py +0 -0
  38. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/tests/test_models.py +0 -0
  39. {pisces_cli-0.1.0 → pisces_cli-0.1.2}/tests/test_patch_engine.py +0 -0
  40. {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`, `.venv-test`, `.venv310`, and other `.venv*` directories.
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
- ```mermaid
130
- flowchart TD
131
- A[pisces scan] --> B[Discover project Python files]
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.
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.1.0"
3
+ __version__ = "0.1.2"
4
4
  __email__ = "mrinmoymatilal1315@gmail.com"
5
5
  __author__ = "Mrinmoy-Matilal"
6
6
  __license__ = "MIT"
@@ -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 .pisces to .gitignore if it exists.abs
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) -> None:
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 .pisces/ is listed in .gitignore."""
172
+ """Ensure Pisces-generated files are listed in .gitignore."""
171
173
  gitignore = project_root / ".gitignore"
172
- entry = ".pisces/"
174
+ entries = (".pisces/", "pisces.toml")
173
175
 
174
176
  if not gitignore.exists():
175
- print_step_running("No .ignore found - creating one ...")
177
+ print_step_running("No .gitignore found - creating one ...")
176
178
  try:
177
- gitignore.write_text(f"# pisces state directory\n{entry}\n", encoding="utf-8")
178
- print_step_ok(".gitignore created with .pisces/entry")
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"could not create .gitignore: {e}")
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
- content = gitignore.read_text(encoding="utf-8")
184
- if entry in content or ".pisces" in content:
185
- print_step_ok(".gitignore already contains .pisces entry - skipping")
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(f"\n# pisces state directory\n{entry}\n")
191
- print_step_ok("Added .pisces/ to .gitignore")
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.0 · MIT License · pip install pisces"
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.0"
7
+ version = "0.1.2"
8
8
  description = "AI-assisted,self healing human-governed Python security remediation patcher"
9
- readme = "README.md"
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
@@ -1408,7 +1408,7 @@ wheels = [
1408
1408
 
1409
1409
  [[package]]
1410
1410
  name = "pisces-cli"
1411
- version = "0.1.0"
1411
+ version = "0.1.2"
1412
1412
  source = { editable = "." }
1413
1413
  dependencies = [
1414
1414
  { name = "anthropic" },
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