codesuture 0.7.3__tar.gz → 1.0.0__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.
- codesuture-1.0.0/LICENSE +21 -0
- codesuture-1.0.0/MANIFEST.in +18 -0
- codesuture-1.0.0/PKG-INFO +430 -0
- codesuture-1.0.0/README.md +405 -0
- codesuture-1.0.0/assets/architecture.png +0 -0
- codesuture-1.0.0/assets/guards.png +0 -0
- codesuture-1.0.0/assets/hero.png +0 -0
- codesuture-1.0.0/codesuture/__init__.py +1 -0
- codesuture-1.0.0/codesuture/alerts/__init__.py +2 -0
- codesuture-1.0.0/codesuture/alerts/channels/__init__.py +1 -0
- codesuture-1.0.0/codesuture/alerts/channels/file_channel.py +139 -0
- codesuture-1.0.0/codesuture/alerts/channels/webhook_channel.py +98 -0
- codesuture-1.0.0/codesuture/alerts/config.py +80 -0
- codesuture-1.0.0/codesuture/alerts/router.py +129 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/audit.py +90 -124
- codesuture-1.0.0/codesuture/cli.py +570 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/codesuture_fix.py +1 -1
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/explain.py +114 -147
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/fingerprint.py +2 -1
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/guard_synthesizer.py +95 -17
- codesuture-1.0.0/codesuture/incidents/__init__.py +4 -0
- codesuture-1.0.0/codesuture/incidents/digest.py +136 -0
- codesuture-1.0.0/codesuture/incidents/incident.py +87 -0
- codesuture-1.0.0/codesuture/incidents/incident_log.py +79 -0
- codesuture-1.0.0/codesuture/incidents/severity.py +45 -0
- codesuture-1.0.0/codesuture/lifecycle.py +203 -0
- codesuture-1.0.0/codesuture/metrics.py +124 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/middleware.py +1 -1
- codesuture-1.0.0/codesuture/middleware_asgi.py +193 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/pattern_matcher.py +41 -8
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/persistence.py +2 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/rollback.py +23 -1
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/sandbox.py +1 -1
- codesuture-1.0.0/codesuture/shadow.py +229 -0
- codesuture-1.0.0/codesuture/suggest.py +304 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/tracer.py +186 -38
- codesuture-1.0.0/codesuture/utils.py +61 -0
- codesuture-1.0.0/codesuture.egg-info/PKG-INFO +430 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture.egg-info/SOURCES.txt +35 -2
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture.egg-info/requires.txt +4 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/pyproject.toml +9 -2
- codesuture-1.0.0/requirements.txt +3 -0
- codesuture-1.0.0/tests/test_alerts.py +249 -0
- codesuture-1.0.0/tests/test_alerts_hard.py +649 -0
- codesuture-1.0.0/tests/test_http_replay.py +103 -0
- codesuture-1.0.0/tests/test_incidents.py +247 -0
- codesuture-1.0.0/tests/test_incidents_hard.py +601 -0
- codesuture-1.0.0/tests/test_lifecycle.py +182 -0
- codesuture-1.0.0/tests/test_metrics.py +115 -0
- codesuture-1.0.0/tests/test_middleware.py +97 -0
- codesuture-1.0.0/tests/test_middleware_asgi.py +249 -0
- codesuture-1.0.0/tests/test_negative.py +131 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/tests/test_pattern_matcher.py +25 -6
- {codesuture-0.7.3 → codesuture-1.0.0}/tests/test_rollback.py +27 -0
- codesuture-1.0.0/tests/test_sandbox.py +166 -0
- codesuture-1.0.0/tests/test_shadow.py +287 -0
- codesuture-1.0.0/tests/test_ship_gate.py +682 -0
- codesuture-1.0.0/tests/test_suggestions.py +295 -0
- codesuture-1.0.0/tests/test_tracer_integration.py +160 -0
- codesuture-0.7.3/.gitignore +0 -53
- codesuture-0.7.3/LICENSE +0 -33
- codesuture-0.7.3/MANIFEST.in +0 -14
- codesuture-0.7.3/PKG-INFO +0 -217
- codesuture-0.7.3/README.md +0 -195
- codesuture-0.7.3/codesuture/__init__.py +0 -1
- codesuture-0.7.3/codesuture/cli.py +0 -130
- codesuture-0.7.3/codesuture/shadow.py +0 -20
- codesuture-0.7.3/codesuture.egg-info/PKG-INFO +0 -217
- codesuture-0.7.3/tests/__init__.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/CHANGELOG.md +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/__main__.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/_eval_fix.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/code_replacer.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/debuggee.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/diff_guard.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/knowledge.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/opcodes.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/plugins/__init__.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/plugins/autonomous.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/rewind.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture/watcher.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture.egg-info/dependency_links.txt +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture.egg-info/entry_points.txt +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/codesuture.egg-info/top_level.txt +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/setup.cfg +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/setup.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/tests/test_e2e.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/tests/test_guard_synthesizer.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/tests/test_harness.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/tests/test_harness2.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/tests/test_new_guards.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/tests/test_opcodes.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/tests/test_persistence.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/tests/test_thread_safety.py +0 -0
- {codesuture-0.7.3 → codesuture-1.0.0}/tests/test_transparency.py +0 -0
codesuture-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MUHAMMAD ABUBAKAR
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
include pyproject.toml
|
|
2
|
+
include README.md
|
|
3
|
+
include CHANGELOG.md
|
|
4
|
+
include LICENSE
|
|
5
|
+
include requirements.txt
|
|
6
|
+
|
|
7
|
+
recursive-include codesuture *.py
|
|
8
|
+
recursive-include assets *.png
|
|
9
|
+
|
|
10
|
+
# Exclude dev-only files from pip sdist
|
|
11
|
+
prune stress
|
|
12
|
+
prune .codesuture_store
|
|
13
|
+
prune .codesuture_incidents
|
|
14
|
+
prune .codesuture_alerts
|
|
15
|
+
exclude .gitignore
|
|
16
|
+
exclude ROADMAP.md
|
|
17
|
+
exclude *.debug.py
|
|
18
|
+
exclude *.zip
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codesuture
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Runtime Python bytecode patcher with guard knowledge base, persistence, and self-healing re-execution
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Source, https://github.com/codesuture/codesuture
|
|
7
|
+
Keywords: bytecode,runtime,patching,self-healing,debugging,null-safety,resilience
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
11
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: bytecode>=0.15.1
|
|
19
|
+
Provides-Extra: autonomous
|
|
20
|
+
Requires-Dist: llama-cpp-python; extra == "autonomous"
|
|
21
|
+
Provides-Extra: test
|
|
22
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
23
|
+
Requires-Dist: pytest-asyncio; extra == "test"
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
<p align="center">
|
|
27
|
+
<img src="assets/hero.png" alt="CodeSuture" width="100%">
|
|
28
|
+
</p>
|
|
29
|
+
|
|
30
|
+
<h1 align="center">CodeSuture</h1>
|
|
31
|
+
|
|
32
|
+
<p align="center">
|
|
33
|
+
<strong>Self-healing runtime for Python. Catches crashes, patches live bytecode, keeps your server alive.</strong>
|
|
34
|
+
</p>
|
|
35
|
+
|
|
36
|
+
<p align="center">
|
|
37
|
+
<a href="#"><img src="https://img.shields.io/badge/version-1.0.0-0d6efd?style=for-the-badge" alt="Version"></a>
|
|
38
|
+
<a href="#"><img src="https://img.shields.io/badge/python-3.11%2B-10b981?style=for-the-badge" alt="Python"></a>
|
|
39
|
+
<a href="#"><img src="https://img.shields.io/badge/tests-416%20passing-10b981?style=for-the-badge" alt="Tests"></a>
|
|
40
|
+
<a href="#"><img src="https://img.shields.io/badge/license-MIT-6366f1?style=for-the-badge" alt="License"></a>
|
|
41
|
+
</p>
|
|
42
|
+
|
|
43
|
+
<p align="center">
|
|
44
|
+
<code>pip install codesuture</code>
|
|
45
|
+
</p>
|
|
46
|
+
|
|
47
|
+
> ⚠️ **CodeSuture modifies live bytecode at runtime.** Use in production at your own risk. Always verify patches with `codesuture audit` and `codesuture explain` before relying on them.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## What is CodeSuture?
|
|
52
|
+
|
|
53
|
+
When a Python program crashes — `AttributeError`, `KeyError`, `ZeroDivisionError`, `IndexError`, `TypeError` — CodeSuture intercepts the exception **at the exact bytecode instruction**, analyzes the crash pattern, injects a deterministic guard into the function's code object **in memory**, and retries execution.
|
|
54
|
+
|
|
55
|
+
No source files are modified. No decorator required. No restart needed.
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
codesuture run your_app.py
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
[CodeSuture] Caught AttributeError: 'NoneType' object has no attribute 'bio'
|
|
63
|
+
[CodeSuture] Applying null_guard on 'profile' ...
|
|
64
|
+
[CodeSuture] Patch applied to get_bio().
|
|
65
|
+
[CodeSuture] Active Shield: Native frame rewound for get_bio() successfully.
|
|
66
|
+
|
|
67
|
+
Session summary:
|
|
68
|
+
Patches applied: 1
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Run it again — the patch loads from disk before the first call:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
[CodeSuture] Already healed: loaded persistent patch for get_bio
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## How It Works
|
|
80
|
+
|
|
81
|
+
<p align="center">
|
|
82
|
+
<img src="assets/architecture.png" alt="CodeSuture Architecture" width="90%">
|
|
83
|
+
</p>
|
|
84
|
+
|
|
85
|
+
CodeSuture operates in five stages:
|
|
86
|
+
|
|
87
|
+
| Stage | What happens |
|
|
88
|
+
|-------|-------------|
|
|
89
|
+
| **① Catch** | `sys.settrace()` intercepts exceptions at the exact frame and bytecode offset |
|
|
90
|
+
| **② Analyze** | The pattern matcher disassembles the failing instruction chain and identifies the crashing variable, operation, and crash type |
|
|
91
|
+
| **③ Patch** | The guard synthesizer injects new bytecode into the function's code object. A semantic diff gate rejects patches that modify too much logic |
|
|
92
|
+
| **④ Rewind** | The execution frame is rewound to re-enter the patched function. On HTTP servers, the full transaction is replayed — the client gets a `200` |
|
|
93
|
+
| **⑤ Persist** | The patched code object is serialized to `.codesuture_store/` with SHA-256 integrity checks and TTL metadata |
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Guard Types
|
|
98
|
+
|
|
99
|
+
<p align="center">
|
|
100
|
+
<img src="assets/guards.png" alt="Guard Types" width="80%">
|
|
101
|
+
</p>
|
|
102
|
+
|
|
103
|
+
CodeSuture ships with **11 deterministic guard types** — each one targets a specific crash pattern and injects the minimal bytecode fix:
|
|
104
|
+
|
|
105
|
+
| Guard | Crash Type | Example | What It Does |
|
|
106
|
+
|-------|-----------|---------|--------------|
|
|
107
|
+
| `null_guard` | `AttributeError` on `None` | `user.profile.bio` | Inserts `if x is None: x = default` before attribute access |
|
|
108
|
+
| `key_guard` | `KeyError` | `config["timeout"]` | Wraps dict access with `.get(key, default)` |
|
|
109
|
+
| `subscript_guard` | `TypeError` subscripting `None` | `data["key"]` when `data` is `None` | Null-checks the container before subscript |
|
|
110
|
+
| `chain_subscript_guard` | Nested subscript failures | `resp["user"]["name"]["first"]` | Guards the entire chain from the root |
|
|
111
|
+
| `index_guard` | `IndexError` (variable index) | `items[i]` when `i >= len(items)` | Bounds-checks `i` against `len(items)` |
|
|
112
|
+
| `list_bound_guard` | `IndexError` (constant index) | `parts[3]` when `len(parts) < 4` | Checks `len(parts) > 3` before access |
|
|
113
|
+
| `division_guard` | `ZeroDivisionError` | `total / count` when `count` is `0` | Substitutes a safe divisor when variable denominator is zero |
|
|
114
|
+
| `str_coerce_guard` | `TypeError` on string concat | `"age: " + age` when `age` is `int` | Wraps non-str variable with `str()` after assignment |
|
|
115
|
+
| `type_coercion_guard` | `TypeError` on conversion | `int("not_a_number")` | Adds type validation before coercion |
|
|
116
|
+
| `file_guard` | `FileNotFoundError` | `open(path)` | Checks `os.path.exists()` before open |
|
|
117
|
+
| `callable_guard` | `TypeError` calling `None` | `callback()` when `callback` is `None` | Returns `None` for unknown callables |
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## CLI Reference
|
|
122
|
+
|
|
123
|
+
### Core Commands
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Run a script with live patching
|
|
127
|
+
codesuture run app.py
|
|
128
|
+
|
|
129
|
+
# Run with full diagnostics
|
|
130
|
+
codesuture run app.py --verbose --shadow --retries 5
|
|
131
|
+
|
|
132
|
+
# Preview patches without applying
|
|
133
|
+
codesuture run app.py --dry-run
|
|
134
|
+
|
|
135
|
+
# Watch mode — auto-restart after patches
|
|
136
|
+
codesuture watch server.py --max-restarts 10
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Inspection & Governance
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# Show all active patches
|
|
143
|
+
codesuture audit
|
|
144
|
+
|
|
145
|
+
# Plain-language explanation of patches
|
|
146
|
+
codesuture explain
|
|
147
|
+
codesuture explain get_user_profile
|
|
148
|
+
|
|
149
|
+
# View incident log
|
|
150
|
+
codesuture incidents
|
|
151
|
+
codesuture incidents --since 2d
|
|
152
|
+
|
|
153
|
+
# Generate markdown incident report
|
|
154
|
+
codesuture digest
|
|
155
|
+
|
|
156
|
+
# View fix suggestions
|
|
157
|
+
codesuture suggest
|
|
158
|
+
|
|
159
|
+
# Export Prometheus metrics
|
|
160
|
+
codesuture metrics
|
|
161
|
+
|
|
162
|
+
# View patch lifecycle states
|
|
163
|
+
codesuture lifecycle show
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Rollback & Cleanup
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# Roll back a specific patch
|
|
170
|
+
codesuture rollback get_user_profile
|
|
171
|
+
|
|
172
|
+
# Preview what would be removed
|
|
173
|
+
codesuture rollback --dry-run
|
|
174
|
+
|
|
175
|
+
# Remove everything — patches, fingerprints, incidents
|
|
176
|
+
codesuture rollback --all
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Alerts
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# View unread alerts
|
|
183
|
+
codesuture alerts
|
|
184
|
+
|
|
185
|
+
# Dismiss alerts for a resolved incident
|
|
186
|
+
codesuture alerts dismiss <incident_id>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## HTTP Recovery
|
|
192
|
+
|
|
193
|
+
CodeSuture patches exceptions inside HTTP request handlers. When a handler crashes and a guard is synthesized, CodeSuture patches the function **mid-request** and replays the transaction in-place. The client receives a response instead of a socket close.
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
[CodeSuture] Caught AttributeError: 'NoneType' object has no attribute 'get_profile'
|
|
197
|
+
[CodeSuture] Applying null_guard on 'get_profile' ...
|
|
198
|
+
[CodeSuture] Patch applied to do_GET().
|
|
199
|
+
[CodeSuture] Transaction replay armed for do_GET().
|
|
200
|
+
[CodeSuture] Transaction replay: retrying patched HTTP handler in-place.
|
|
201
|
+
127.0.0.1 - - "GET /user-data HTTP/1.1" 200 -
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Every patched response carries a transparency header:
|
|
205
|
+
|
|
206
|
+
```http
|
|
207
|
+
HTTP/1.0 200 OK
|
|
208
|
+
Content-type: application/json
|
|
209
|
+
X-CodeSuture: patched=1; guard=null_guard; target=get_profile
|
|
210
|
+
|
|
211
|
+
{"result": null}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Framework Middleware
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
# WSGI (Flask, Django, Bottle, etc.)
|
|
218
|
+
from codesuture.middleware import CodeSutureMiddleware
|
|
219
|
+
app = CodeSutureMiddleware(your_wsgi_app)
|
|
220
|
+
|
|
221
|
+
# ASGI (FastAPI, Starlette, etc.)
|
|
222
|
+
from codesuture.middleware_asgi import CodeSutureASGIMiddleware
|
|
223
|
+
app = CodeSutureASGIMiddleware(your_asgi_app)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Incident Intelligence
|
|
229
|
+
|
|
230
|
+
Every crash CodeSuture intercepts is logged as a structured incident with automatic severity classification:
|
|
231
|
+
|
|
232
|
+
| Severity | When |
|
|
233
|
+
|----------|------|
|
|
234
|
+
| **CRITICAL** | Callable replacement, sensitive modules (auth, payment, billing) |
|
|
235
|
+
| **HIGH** | First occurrence, HTTP mutating methods (POST/PUT/DELETE), chain subscripts |
|
|
236
|
+
| **MEDIUM** | Standard guards (null, key, division, index) after first occurrence |
|
|
237
|
+
| **LOW** | Repeat patterns, file guards, string coercion |
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
$ codesuture incidents
|
|
241
|
+
|
|
242
|
+
Time Severity Function Guard Target Status
|
|
243
|
+
──────────────────── ────────── ───────────────────────── ──────────────────── ─────────────── ──────────
|
|
244
|
+
2026-05-26T19:05:55 MEDIUM render_user_card null_guard user patched
|
|
245
|
+
2026-05-26T19:05:55 HIGH format_weather_report chain_subscript_guard data patched
|
|
246
|
+
2026-05-26T19:05:56 MEDIUM compute_metrics division_guard success patched
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
$ codesuture digest
|
|
251
|
+
|
|
252
|
+
# CodeSuture Daily Incident Report — 2026-05-26
|
|
253
|
+
|
|
254
|
+
## Summary
|
|
255
|
+
- **Total incidents:** 3
|
|
256
|
+
- **CRITICAL:** 0 | **HIGH:** 1 | **MEDIUM:** 2 | **LOW:** 0
|
|
257
|
+
- **Unique crash patterns:** 3
|
|
258
|
+
- **Functions patched:** 3
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Alert System
|
|
264
|
+
|
|
265
|
+
CodeSuture routes incidents to alert channels based on severity:
|
|
266
|
+
|
|
267
|
+
- **File alerts** — Markdown files written to `.codesuture_alerts/`
|
|
268
|
+
- **Webhook alerts** — HTTP POST to your alerting endpoint (Slack, PagerDuty, etc.)
|
|
269
|
+
- **Escalation** — Functions patched 5+ times in 24 hours are auto-escalated
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
$ codesuture alerts
|
|
273
|
+
|
|
274
|
+
CodeSuture — Unread Alerts
|
|
275
|
+
|
|
276
|
+
[HIGH] format_weather_report crashed with KeyError, patched with chain_subscript_guard
|
|
277
|
+
Escalating get_user_display from HIGH to CRITICAL (patched 5 times in 24h)
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Shadow Execution
|
|
283
|
+
|
|
284
|
+
With `--shadow`, CodeSuture runs the original (unpatched) function alongside the patched version and compares results:
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
codesuture run app.py --shadow
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
| Verdict | Meaning |
|
|
291
|
+
|---------|---------|
|
|
292
|
+
| **JUSTIFIED** | Original crashes, patched succeeds — the patch is necessary |
|
|
293
|
+
| **UNNECESSARY** | Both produce the same result — consider removing the patch |
|
|
294
|
+
| **DIVERGENT** | Results differ — the patch changes behavior, review recommended |
|
|
295
|
+
|
|
296
|
+
Shadow-verified patches get upgraded to **VERIFIED** confidence in fix suggestions.
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Fix Suggestions
|
|
301
|
+
|
|
302
|
+
CodeSuture generates concrete source-code fix suggestions for every active patch:
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
$ codesuture suggest
|
|
306
|
+
|
|
307
|
+
Function: render_user_card
|
|
308
|
+
Guard: null_guard on 'profile'
|
|
309
|
+
Confidence: LIKELY
|
|
310
|
+
|
|
311
|
+
--- a/app.py
|
|
312
|
+
+++ b/app.py
|
|
313
|
+
@@ -15,1 +15,1 @@
|
|
314
|
+
- bio = user.profile.bio
|
|
315
|
+
+ bio = user.profile.bio if user.profile is not None else ''
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Confidence levels:
|
|
319
|
+
- **VERIFIED** — Shadow execution confirmed the fix works
|
|
320
|
+
- **LIKELY** — Deterministic guard with high confidence
|
|
321
|
+
- **EXPERIMENTAL** — Complex guard, review recommended
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Lifecycle Management
|
|
326
|
+
|
|
327
|
+
Every patch transitions through a state machine:
|
|
328
|
+
|
|
329
|
+
```
|
|
330
|
+
DETECTED → PATCHED → PERSISTED → SUGGESTED → VERIFIED → FIXED
|
|
331
|
+
↓ ↓
|
|
332
|
+
REPLAYED EXPIRED
|
|
333
|
+
↓
|
|
334
|
+
ROLLED_BACK
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
$ codesuture lifecycle show
|
|
339
|
+
|
|
340
|
+
Function State Age TTL
|
|
341
|
+
get_bio PERSISTED 2d 7d
|
|
342
|
+
compute_ratio VERIFIED 1d 7d
|
|
343
|
+
parse_config EXPIRED 8d 7d ← needs attention
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## Prometheus Metrics
|
|
349
|
+
|
|
350
|
+
Export patch metrics in Prometheus text format:
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
$ codesuture metrics
|
|
354
|
+
|
|
355
|
+
# HELP codesuture_incidents_total Total incidents recorded
|
|
356
|
+
# TYPE codesuture_incidents_total counter
|
|
357
|
+
codesuture_incidents_total 20
|
|
358
|
+
codesuture_patches_total{guard_type="null_guard"} 12
|
|
359
|
+
codesuture_patches_total{guard_type="key_guard"} 5
|
|
360
|
+
codesuture_patches_total{guard_type="division_guard"} 3
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## Safety & Security
|
|
366
|
+
|
|
367
|
+
| Feature | What it prevents |
|
|
368
|
+
|---------|-----------------|
|
|
369
|
+
| **Semantic diff gate** | Rejects patches that modify too many instructions. The engine never corrupts a complex function to fix a simple crash |
|
|
370
|
+
| **SHA-256 integrity** | Persisted `.code` files are checksummed. Tampered files are refused on load |
|
|
371
|
+
| **Patch validation** | Synthesized bytecode is checked for `LOAD_FAST` references to variables not in `co_varnames`. Invalid patches are rejected |
|
|
372
|
+
| **Original code backup** | Pre-patch code objects are stored in `_ORIGINAL_CODES` for runtime rollback |
|
|
373
|
+
| **Patch TTL** | Every patch carries a time-to-live. Expired patches warn to fix the root cause |
|
|
374
|
+
| **Thread safety** | All shared state protected by locks. Safe under free-threaded Python 3.13+ (no-GIL) |
|
|
375
|
+
| **Caller-aware propagation** | After patching, `gc.get_referrers` updates closures, bound methods, and partials |
|
|
376
|
+
| **Runtime rollback** | `codesuture rollback` removes disk files AND restores original code in the running process |
|
|
377
|
+
| **CPython portability** | Version-aware opcode sets handle 3.11, 3.12, and 3.13+ instruction differences |
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## Known Limitations
|
|
382
|
+
|
|
383
|
+
| Limitation | Detail |
|
|
384
|
+
|-----------|--------|
|
|
385
|
+
| **Python 3.11+ only** | Depends on CPython bytecode structures introduced in 3.11 |
|
|
386
|
+
| **First crash leaks** | The initial exception propagates to the caller. The patch prevents recurrence on subsequent calls |
|
|
387
|
+
| **Comprehensions** | List/dict/set/generator comprehensions are anonymous nested code objects — CodeSuture logs a warning and skips them |
|
|
388
|
+
| **Semantic bugs** | CodeSuture fixes structural crashes (null access, missing keys, type mismatches). Logic errors that produce wrong results without crashing cannot be detected |
|
|
389
|
+
| **Single-process** | Patches apply per-process. `.codesuture_store/` is shared on disk for cross-restart persistence |
|
|
390
|
+
| **Async (experimental)** | Standard `async def` functions are patched. Async generators and deep `await` chains may not be handled correctly |
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## What CodeSuture Is Not
|
|
395
|
+
|
|
396
|
+
**Not a logger.** It doesn't record exceptions and move on. It patches the function and retries.
|
|
397
|
+
|
|
398
|
+
**Not a static analyzer.** It operates at runtime on live bytecode, not on source files.
|
|
399
|
+
|
|
400
|
+
**Not autonomous by default.** All patches are deterministic rule-based guards. An opt-in `--autonomous` flag exists for experimental LLM-powered suggestions, but it never auto-applies.
|
|
401
|
+
|
|
402
|
+
**Not a replacement for fixing bugs.** CodeSuture is a runtime safety net. The `suggest` command tells you exactly what source code to change. The `lifecycle` system tracks patch age. Expired patches mean you should have fixed the root cause by now.
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## Installation
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
pip install codesuture
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
Requires **Python 3.11+** and the [`bytecode`](https://pypi.org/project/bytecode/) library (installed automatically).
|
|
413
|
+
|
|
414
|
+
For experimental LLM-powered autonomous mode:
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
pip install "codesuture[autonomous]"
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## License
|
|
423
|
+
|
|
424
|
+
MIT. See [LICENSE](LICENSE) for details.
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
<p align="center">
|
|
429
|
+
<sub>Built with obsession, not sleep. If CodeSuture saved your server at 3 AM, consider giving it a ⭐.</sub>
|
|
430
|
+
</p>
|