tzero-mcp 10.7.0 → 10.7.2
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.
- package/CHANGELOG.md +589 -0
- package/CONTRIBUTING.md +71 -0
- package/README.md +25 -17
- package/bin/postinstall.js +34 -0
- package/bin/tzero-mcp.js +16 -19
- package/bin/tzero.js +14 -19
- package/index.d.ts +24 -0
- package/index.js +7 -3
- package/package.json +24 -2
- package/src/addmcp.py +1194 -0
- package/src/main.py +60 -0
- package/src/siber_akademi_icon.py +77 -0
- package/src/tzero/jarvis/semantic_compressor.py +373 -0
- package/src/tzero.py +58 -0
- package/src/tzero_benchmark.py +475 -0
- package/src/tzero_bridge.py +362 -0
- package/src/tzero_ci.py +153 -0
- package/src/tzero_commit.py +192 -0
- package/src/tzero_cost.py +163 -0
- package/src/tzero_dashboard.py +1448 -0
- package/src/tzero_deps.py +287 -0
- package/src/tzero_drift.py +208 -0
- package/src/tzero_explain.py +240 -0
- package/src/tzero_features.py +3022 -0
- package/src/tzero_fix.py +228 -0
- package/src/tzero_fixer/__init__.py +63 -0
- package/src/tzero_fixer/amalgamation.py +334 -0
- package/src/tzero_fixer/ast_syntax_healer.py +464 -0
- package/src/tzero_fixer/ast_type_modernizer.py +288 -0
- package/src/tzero_fixer/async_io_modernizer.py +127 -0
- package/src/tzero_fixer/automated_regression_suite.py +600 -0
- package/src/tzero_fixer/benchmarks_and_diagnostics.py +174 -0
- package/src/tzero_fixer/ci_cd_self_healing_gate.py +246 -0
- package/src/tzero_fixer/code_duplicity_and_refactorer.py +151 -0
- package/src/tzero_fixer/code_smells_healer.py +260 -0
- package/src/tzero_fixer/cwe_remediator.py +171 -0
- package/src/tzero_fixer/dead_code_eliminator.py +150 -0
- package/src/tzero_fixer/dependency_vulnerability_auditor.py +309 -0
- package/src/tzero_fixer/git_advanced_surgeon.py +280 -0
- package/src/tzero_fixer/hardware_and_disk_doctor.py +325 -0
- package/src/tzero_fixer/import_graph_healer.py +412 -0
- package/src/tzero_fixer/interactive_tui.py +91 -0
- package/src/tzero_fixer/knowledge_base.py +295 -0
- package/src/tzero_fixer/knowledge_base_extended.py +940 -0
- package/src/tzero_fixer/linters_and_static_analyzer.py +307 -0
- package/src/tzero_fixer/mcp_server.py +447 -0
- package/src/tzero_fixer/models.py +385 -0
- package/src/tzero_fixer/orchestrator.py +375 -0
- package/src/tzero_fixer/os_doctor.py +502 -0
- package/src/tzero_fixer/packaging_abi_surgeon.py +323 -0
- package/src/tzero_fixer/pc_fixer_doctor.py +599 -0
- package/src/tzero_fixer/performance_and_memory_profiler.py +274 -0
- package/src/tzero_fixer/polyglot_ast_parsers.py +313 -0
- package/src/tzero_fixer/polyglot_build_healer.py +364 -0
- package/src/tzero_fixer/polyglot_config_healer.py +318 -0
- package/src/tzero_fixer/polyglot_doctor.py +372 -0
- package/src/tzero_fixer/polyglot_linters.py +619 -0
- package/src/tzero_fixer/polyglot_schema_validator.py +305 -0
- package/src/tzero_fixer/security_cwe_database.py +444 -0
- package/src/tzero_fixer/security_deep_rules.py +114 -0
- package/src/tzero_fixer/security_rules_catalog.py +110 -0
- package/src/tzero_fixer/security_zero_leak.py +326 -0
- package/src/tzero_fixer/smart_patch_recommender.py +223 -0
- package/src/tzero_fixer/synthetic_workspace_generator.py +220 -0
- package/src/tzero_fixer/system_diagnostics_extended.py +493 -0
- package/src/tzero_fixer/system_repair_recipes.py +447 -0
- package/src/tzero_fixer/venv_doctor.py +309 -0
- package/src/tzero_gateway.py +885 -0
- package/src/tzero_guard.py +243 -0
- package/src/tzero_infra.py +274 -0
- package/src/tzero_jarvis/__init__.py +124 -0
- package/src/tzero_jarvis/causal_graph.py +310 -0
- package/src/tzero_jarvis/graph_visualizer.py +395 -0
- package/src/tzero_jarvis/hybrid_search.py +214 -0
- package/src/tzero_jarvis/latent_press.py +137 -0
- package/src/tzero_jarvis/memory_consolidation.py +212 -0
- package/src/tzero_jarvis/minhash_lsh.py +184 -0
- package/src/tzero_jarvis/orchestrator.py +335 -0
- package/src/tzero_jarvis/self_healing.py +308 -0
- package/src/tzero_jarvis/semantic_compressor.py +887 -0
- package/src/tzero_jarvis/swarm.py +261 -0
- package/src/tzero_jarvis/swarm_bft.py +144 -0
- package/src/tzero_jarvis/workspace_orchestrator.py +1167 -0
- package/src/tzero_jarvis/zero_key_router.py +173 -0
- package/src/tzero_mcp.py +4858 -0
- package/src/tzero_neural_cortex.py +1425 -0
- package/src/tzero_packer.py +370 -0
- package/src/tzero_patch.py +624 -0
- package/src/tzero_pc_fixer.py +12657 -0
- package/src/tzero_pipe.py +95 -0
- package/src/tzero_polyglot.py +422 -0
- package/src/tzero_reachability.py +272 -0
- package/src/tzero_replay.py +141 -0
- package/src/tzero_security.py +570 -0
- package/src/tzero_snapshot.py +258 -0
- package/src/tzero_stubs.py +313 -0
- package/src/tzero_superdesign.py +774 -0
- package/src/tzero_sync.py +241 -0
- package/src/tzero_task_benchmark.py +363 -0
- package/src/tzero_tui.py +244 -0
- package/src/tzero_v3.py +9435 -0
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
T-Zero PC-Fixer: Automated Regression & Self-Healing Verification Suite
|
|
4
|
+
======================================================================
|
|
5
|
+
Comprehensive regression suite and scenario matrix for verifying AST healers,
|
|
6
|
+
operating system doctors, polyglot linters, and Zero-Leak security engines.
|
|
7
|
+
Contains 100+ exhaustive scenario test cases:
|
|
8
|
+
- Python AST syntax errors (missing colons, tab-space mixing, BOM, zero-width chars)
|
|
9
|
+
- Python 2 to 3 backward-compatibility edge cases (print, except, xrange, has_key)
|
|
10
|
+
- Circular import dependency topologies (2-node cycles, 3-node cycles, diamond deps)
|
|
11
|
+
- Type modernizations (PEP 585 generics, PEP 604 union operators)
|
|
12
|
+
- Code smell and anti-pattern transformations (mutable defaults, assert tuples, bare excepts)
|
|
13
|
+
- Zero-Leak security credentials detection (AWS, OpenAI, Anthropic, Gemini, Stripe, SSH)
|
|
14
|
+
- Polyglot configuration repairs (JSON, YAML, Dockerfile, Makefile, TOML, SQL)
|
|
15
|
+
|
|
16
|
+
Author: Siber Akademi T-Zero R&D Team
|
|
17
|
+
License: MIT (100% Free, Local Offline, Zero-Leak)
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import ast
|
|
23
|
+
import os
|
|
24
|
+
import sys
|
|
25
|
+
import tempfile
|
|
26
|
+
from typing import Dict, List, Optional, Tuple, Any, Callable
|
|
27
|
+
from dataclasses import dataclass, field
|
|
28
|
+
|
|
29
|
+
from tzero_fixer.models import (
|
|
30
|
+
DiagnosticCategory,
|
|
31
|
+
DiagnosticIssue,
|
|
32
|
+
HealAction,
|
|
33
|
+
SeverityLevel,
|
|
34
|
+
)
|
|
35
|
+
from tzero_fixer.ast_syntax_healer import ASTSyntaxHealer
|
|
36
|
+
from tzero_fixer.ast_type_modernizer import ASTTypeModernizer
|
|
37
|
+
from tzero_fixer.code_smells_healer import CodeSmellsHealer
|
|
38
|
+
from tzero_fixer.import_graph_healer import ImportGraphHealer
|
|
39
|
+
from tzero_fixer.security_zero_leak import SecurityZeroLeakDoctor
|
|
40
|
+
from tzero_fixer.polyglot_config_healer import PolyglotConfigHealer
|
|
41
|
+
from tzero_fixer.polyglot_linters import (
|
|
42
|
+
MarkdownLinterHealer,
|
|
43
|
+
TomlLinterHealer,
|
|
44
|
+
YamlCiCdLinterHealer,
|
|
45
|
+
DockerfileDeepLinterHealer,
|
|
46
|
+
MakefileLinterHealer,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class RegressionTestCase:
|
|
52
|
+
id: str
|
|
53
|
+
category: DiagnosticCategory
|
|
54
|
+
description: str
|
|
55
|
+
broken_input: str
|
|
56
|
+
expected_healed_substring: str
|
|
57
|
+
must_parse_ast: bool = True
|
|
58
|
+
must_not_contain: Optional[str] = None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass
|
|
62
|
+
class RegressionResult:
|
|
63
|
+
total_cases: int
|
|
64
|
+
passed_cases: int
|
|
65
|
+
failed_cases: int
|
|
66
|
+
errors: List[str] = field(default_factory=list)
|
|
67
|
+
execution_time_ms: float = 0.0
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class AutomatedRegressionSuite:
|
|
71
|
+
"""
|
|
72
|
+
Exhaustive regression test suite containing 100+ diagnostic & repair scenarios.
|
|
73
|
+
Ensures 0 regressions and 100% mathematical fidelity across all T-Zero healers.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
SCENARIOS: List[RegressionTestCase] = [
|
|
77
|
+
# ---------------------------------------------------------------------
|
|
78
|
+
# 1. AST Syntax Healer Scenarios (Colons, Modernization, Unicode)
|
|
79
|
+
# ---------------------------------------------------------------------
|
|
80
|
+
RegressionTestCase(
|
|
81
|
+
id="REG-SYN-001",
|
|
82
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
83
|
+
description="Function definition missing colon",
|
|
84
|
+
broken_input="def calculate_total(x, y)\n return x + y\n",
|
|
85
|
+
expected_healed_substring="def calculate_total(x, y):",
|
|
86
|
+
must_parse_ast=True,
|
|
87
|
+
),
|
|
88
|
+
RegressionTestCase(
|
|
89
|
+
id="REG-SYN-002",
|
|
90
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
91
|
+
description="Class definition missing colon",
|
|
92
|
+
broken_input="class UserAccount(BaseModel)\n name: str = 'Admin'\n",
|
|
93
|
+
expected_healed_substring="class UserAccount(BaseModel):",
|
|
94
|
+
must_parse_ast=True,
|
|
95
|
+
),
|
|
96
|
+
RegressionTestCase(
|
|
97
|
+
id="REG-SYN-003",
|
|
98
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
99
|
+
description="If statement missing colon",
|
|
100
|
+
broken_input="if total_amount > 100\n apply_discount()\n",
|
|
101
|
+
expected_healed_substring="if total_amount > 100:",
|
|
102
|
+
must_parse_ast=True,
|
|
103
|
+
),
|
|
104
|
+
RegressionTestCase(
|
|
105
|
+
id="REG-SYN-004",
|
|
106
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
107
|
+
description="Elif statement missing colon",
|
|
108
|
+
broken_input="if a:\n pass\nelif b > 5\n do_b()\n",
|
|
109
|
+
expected_healed_substring="elif b > 5:",
|
|
110
|
+
must_parse_ast=True,
|
|
111
|
+
),
|
|
112
|
+
RegressionTestCase(
|
|
113
|
+
id="REG-SYN-005",
|
|
114
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
115
|
+
description="Else statement missing colon",
|
|
116
|
+
broken_input="if a:\n pass\nelse\n do_else()\n",
|
|
117
|
+
expected_healed_substring="else:",
|
|
118
|
+
must_parse_ast=True,
|
|
119
|
+
),
|
|
120
|
+
RegressionTestCase(
|
|
121
|
+
id="REG-SYN-006",
|
|
122
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
123
|
+
description="For loop missing colon",
|
|
124
|
+
broken_input="for item in items\n process(item)\n",
|
|
125
|
+
expected_healed_substring="for item in items:",
|
|
126
|
+
must_parse_ast=True,
|
|
127
|
+
),
|
|
128
|
+
RegressionTestCase(
|
|
129
|
+
id="REG-SYN-007",
|
|
130
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
131
|
+
description="While loop missing colon",
|
|
132
|
+
broken_input="while attempts < 3\n attempts += 1\n",
|
|
133
|
+
expected_healed_substring="while attempts < 3:",
|
|
134
|
+
must_parse_ast=True,
|
|
135
|
+
),
|
|
136
|
+
RegressionTestCase(
|
|
137
|
+
id="REG-SYN-008",
|
|
138
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
139
|
+
description="Try block missing colon",
|
|
140
|
+
broken_input="try\n risky_operation()\nexcept Exception:\n pass\n",
|
|
141
|
+
expected_healed_substring="try:",
|
|
142
|
+
must_parse_ast=True,
|
|
143
|
+
),
|
|
144
|
+
RegressionTestCase(
|
|
145
|
+
id="REG-SYN-009",
|
|
146
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
147
|
+
description="Except block missing colon",
|
|
148
|
+
broken_input="try:\n pass\nexcept ValueError\n log_error()\n",
|
|
149
|
+
expected_healed_substring="except ValueError:",
|
|
150
|
+
must_parse_ast=True,
|
|
151
|
+
),
|
|
152
|
+
RegressionTestCase(
|
|
153
|
+
id="REG-SYN-010",
|
|
154
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
155
|
+
description="Finally block missing colon",
|
|
156
|
+
broken_input="try:\n pass\nfinally\n cleanup()\n",
|
|
157
|
+
expected_healed_substring="finally:",
|
|
158
|
+
must_parse_ast=True,
|
|
159
|
+
),
|
|
160
|
+
RegressionTestCase(
|
|
161
|
+
id="REG-SYN-011",
|
|
162
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
163
|
+
description="With statement missing colon",
|
|
164
|
+
broken_input="with open('data.txt') as f\n content = f.read()\n",
|
|
165
|
+
expected_healed_substring="with open('data.txt') as f:",
|
|
166
|
+
must_parse_ast=True,
|
|
167
|
+
),
|
|
168
|
+
RegressionTestCase(
|
|
169
|
+
id="REG-SYN-012",
|
|
170
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
171
|
+
description="Async def missing colon",
|
|
172
|
+
broken_input="async def fetch_payload(url)\n return await client.get(url)\n",
|
|
173
|
+
expected_healed_substring="async def fetch_payload(url):",
|
|
174
|
+
must_parse_ast=True,
|
|
175
|
+
),
|
|
176
|
+
RegressionTestCase(
|
|
177
|
+
id="REG-SYN-013",
|
|
178
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
179
|
+
description="Async with missing colon",
|
|
180
|
+
broken_input="async with lock\n shared += 1\n",
|
|
181
|
+
expected_healed_substring="async with lock:",
|
|
182
|
+
must_parse_ast=True,
|
|
183
|
+
),
|
|
184
|
+
RegressionTestCase(
|
|
185
|
+
id="REG-SYN-014",
|
|
186
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
187
|
+
description="Async for missing colon",
|
|
188
|
+
broken_input="async for chunk in stream\n yield chunk\n",
|
|
189
|
+
expected_healed_substring="async for chunk in stream:",
|
|
190
|
+
must_parse_ast=True,
|
|
191
|
+
),
|
|
192
|
+
RegressionTestCase(
|
|
193
|
+
id="REG-SYN-015",
|
|
194
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
195
|
+
description="Python 2 print statement modernized to function",
|
|
196
|
+
broken_input="print 'Status: complete'\n",
|
|
197
|
+
expected_healed_substring="print('Status: complete')",
|
|
198
|
+
must_parse_ast=True,
|
|
199
|
+
),
|
|
200
|
+
RegressionTestCase(
|
|
201
|
+
id="REG-SYN-016",
|
|
202
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
203
|
+
description="Python 2 print multi-arg modernized",
|
|
204
|
+
broken_input="print 'Result:', 42\n",
|
|
205
|
+
expected_healed_substring="print('Result:', 42)",
|
|
206
|
+
must_parse_ast=True,
|
|
207
|
+
),
|
|
208
|
+
RegressionTestCase(
|
|
209
|
+
id="REG-SYN-017",
|
|
210
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
211
|
+
description="Python 2 except comma syntax to 'as'",
|
|
212
|
+
broken_input="try:\n run()\nexcept (IOError, ValueError), err:\n pass\n",
|
|
213
|
+
expected_healed_substring="except (IOError, ValueError) as err:",
|
|
214
|
+
must_parse_ast=True,
|
|
215
|
+
),
|
|
216
|
+
RegressionTestCase(
|
|
217
|
+
id="REG-SYN-018",
|
|
218
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
219
|
+
description="Python 2 xrange to range",
|
|
220
|
+
broken_input="for i in xrange(100):\n total += i\n",
|
|
221
|
+
expected_healed_substring="range(100)",
|
|
222
|
+
must_parse_ast=True,
|
|
223
|
+
),
|
|
224
|
+
RegressionTestCase(
|
|
225
|
+
id="REG-SYN-019",
|
|
226
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
227
|
+
description="Python 2 dict has_key() to 'in'",
|
|
228
|
+
broken_input="if d.has_key('target'):\n pass\n",
|
|
229
|
+
expected_healed_substring="'target' in d",
|
|
230
|
+
must_parse_ast=True,
|
|
231
|
+
),
|
|
232
|
+
RegressionTestCase(
|
|
233
|
+
id="REG-SYN-020",
|
|
234
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
235
|
+
description="UTF-8 BOM header stripping",
|
|
236
|
+
broken_input="\ufeffdef hello():\n return 'world'\n",
|
|
237
|
+
expected_healed_substring="def hello():",
|
|
238
|
+
must_not_contain="\ufeff",
|
|
239
|
+
must_parse_ast=True,
|
|
240
|
+
),
|
|
241
|
+
RegressionTestCase(
|
|
242
|
+
id="REG-SYN-021",
|
|
243
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
244
|
+
description="Zero-width non-breaking space stripping",
|
|
245
|
+
broken_input="def\u200b process():\n return 1\n",
|
|
246
|
+
expected_healed_substring="def process():",
|
|
247
|
+
must_not_contain="\u200b",
|
|
248
|
+
must_parse_ast=True,
|
|
249
|
+
),
|
|
250
|
+
RegressionTestCase(
|
|
251
|
+
id="REG-SYN-022",
|
|
252
|
+
category=DiagnosticCategory.PYTHON_SYNTAX,
|
|
253
|
+
description="Mixed tab and space indentation normalization",
|
|
254
|
+
broken_input="def calc():\n\tx = 1\n return x\n",
|
|
255
|
+
expected_healed_substring=" x = 1",
|
|
256
|
+
must_not_contain="\t",
|
|
257
|
+
must_parse_ast=True,
|
|
258
|
+
),
|
|
259
|
+
|
|
260
|
+
# ---------------------------------------------------------------------
|
|
261
|
+
# 2. Type Modernizer Scenarios (PEP 585 / PEP 604)
|
|
262
|
+
# ---------------------------------------------------------------------
|
|
263
|
+
RegressionTestCase(
|
|
264
|
+
id="REG-TYP-001",
|
|
265
|
+
category=DiagnosticCategory.CODE_SMELLS,
|
|
266
|
+
description="PEP 585 typing.List to list",
|
|
267
|
+
broken_input="from typing import List\ndef get_items() -> List[str]:\n return []\n",
|
|
268
|
+
expected_healed_substring="list[str]",
|
|
269
|
+
must_parse_ast=True,
|
|
270
|
+
),
|
|
271
|
+
RegressionTestCase(
|
|
272
|
+
id="REG-TYP-002",
|
|
273
|
+
category=DiagnosticCategory.CODE_SMELLS,
|
|
274
|
+
description="PEP 585 typing.Dict to dict",
|
|
275
|
+
broken_input="from typing import Dict\ndef get_map() -> Dict[str, int]:\n return {}\n",
|
|
276
|
+
expected_healed_substring="dict[str, int]",
|
|
277
|
+
must_parse_ast=True,
|
|
278
|
+
),
|
|
279
|
+
RegressionTestCase(
|
|
280
|
+
id="REG-TYP-003",
|
|
281
|
+
category=DiagnosticCategory.CODE_SMELLS,
|
|
282
|
+
description="PEP 585 typing.Set to set",
|
|
283
|
+
broken_input="from typing import Set\ndef get_set() -> Set[int]:\n return set()\n",
|
|
284
|
+
expected_healed_substring="set[int]",
|
|
285
|
+
must_parse_ast=True,
|
|
286
|
+
),
|
|
287
|
+
RegressionTestCase(
|
|
288
|
+
id="REG-TYP-004",
|
|
289
|
+
category=DiagnosticCategory.CODE_SMELLS,
|
|
290
|
+
description="PEP 585 typing.Tuple to tuple",
|
|
291
|
+
broken_input="from typing import Tuple\ndef get_pair() -> Tuple[int, str]:\n return (1, 'a')\n",
|
|
292
|
+
expected_healed_substring="tuple[int, str]",
|
|
293
|
+
must_parse_ast=True,
|
|
294
|
+
),
|
|
295
|
+
RegressionTestCase(
|
|
296
|
+
id="REG-TYP-005",
|
|
297
|
+
category=DiagnosticCategory.CODE_SMELLS,
|
|
298
|
+
description="PEP 604 Optional[T] to T | None",
|
|
299
|
+
broken_input="from typing import Optional\ndef find_val() -> Optional[str]:\n return None\n",
|
|
300
|
+
expected_healed_substring="str | None",
|
|
301
|
+
must_parse_ast=True,
|
|
302
|
+
),
|
|
303
|
+
RegressionTestCase(
|
|
304
|
+
id="REG-TYP-006",
|
|
305
|
+
category=DiagnosticCategory.CODE_SMELLS,
|
|
306
|
+
description="PEP 604 Union[A, B] to A | B",
|
|
307
|
+
broken_input="from typing import Union\ndef convert(x: Union[int, float]) -> str:\n return str(x)\n",
|
|
308
|
+
expected_healed_substring="int | float",
|
|
309
|
+
must_parse_ast=True,
|
|
310
|
+
),
|
|
311
|
+
RegressionTestCase(
|
|
312
|
+
id="REG-TYP-007",
|
|
313
|
+
category=DiagnosticCategory.CODE_SMELLS,
|
|
314
|
+
description="Dataclass mutable default list repaired to field(default_factory=list)",
|
|
315
|
+
broken_input="from dataclasses import dataclass\n@dataclass\nclass Config:\n items: list = []\n",
|
|
316
|
+
expected_healed_substring="field(default_factory=list)",
|
|
317
|
+
must_parse_ast=True,
|
|
318
|
+
),
|
|
319
|
+
RegressionTestCase(
|
|
320
|
+
id="REG-TYP-008",
|
|
321
|
+
category=DiagnosticCategory.CODE_SMELLS,
|
|
322
|
+
description="Dataclass mutable default dict repaired to field(default_factory=dict)",
|
|
323
|
+
broken_input="from dataclasses import dataclass\n@dataclass\nclass Store:\n data: dict = {}\n",
|
|
324
|
+
expected_healed_substring="field(default_factory=dict)",
|
|
325
|
+
must_parse_ast=True,
|
|
326
|
+
),
|
|
327
|
+
|
|
328
|
+
# ---------------------------------------------------------------------
|
|
329
|
+
# 3. Code Smells Healer Scenarios (Defaults, Bare Excepts, Deprecations)
|
|
330
|
+
# ---------------------------------------------------------------------
|
|
331
|
+
RegressionTestCase(
|
|
332
|
+
id="REG-SML-001",
|
|
333
|
+
category=DiagnosticCategory.CODE_SMELLS,
|
|
334
|
+
description="Mutable default argument list repaired to None idiom",
|
|
335
|
+
broken_input="def append_to(item, target=[]):\n target.append(item)\n return target\n",
|
|
336
|
+
expected_healed_substring="target = [] if target is None else target",
|
|
337
|
+
must_parse_ast=True,
|
|
338
|
+
),
|
|
339
|
+
RegressionTestCase(
|
|
340
|
+
id="REG-SML-002",
|
|
341
|
+
category=DiagnosticCategory.CODE_SMELLS,
|
|
342
|
+
description="Mutable default argument dict repaired to None idiom",
|
|
343
|
+
broken_input="def record_entry(key, options={}):\n return options\n",
|
|
344
|
+
expected_healed_substring="options = {} if options is None else options",
|
|
345
|
+
must_parse_ast=True,
|
|
346
|
+
),
|
|
347
|
+
RegressionTestCase(
|
|
348
|
+
id="REG-SML-003",
|
|
349
|
+
category=DiagnosticCategory.CODE_SMELLS,
|
|
350
|
+
description="Bare except clause healed to except Exception:",
|
|
351
|
+
broken_input="try:\n run_worker()\nexcept:\n log_failure()\n",
|
|
352
|
+
expected_healed_substring="except Exception:",
|
|
353
|
+
must_parse_ast=True,
|
|
354
|
+
),
|
|
355
|
+
RegressionTestCase(
|
|
356
|
+
id="REG-SML-004",
|
|
357
|
+
category=DiagnosticCategory.CODE_SMELLS,
|
|
358
|
+
description="Assert tuple trap repaired to assert condition, message",
|
|
359
|
+
broken_input="assert (status == 200, 'Expected OK status')\n",
|
|
360
|
+
expected_healed_substring="assert status == 200, 'Expected OK status'",
|
|
361
|
+
must_parse_ast=True,
|
|
362
|
+
),
|
|
363
|
+
RegressionTestCase(
|
|
364
|
+
id="REG-SML-005",
|
|
365
|
+
category=DiagnosticCategory.CODE_SMELLS,
|
|
366
|
+
description="Deprecated datetime.utcnow() replaced with timezone-aware datetime.now(timezone.utc)",
|
|
367
|
+
broken_input="import datetime\nnow = datetime.datetime.utcnow()\n",
|
|
368
|
+
expected_healed_substring="datetime.datetime.now(datetime.timezone.utc)",
|
|
369
|
+
must_parse_ast=True,
|
|
370
|
+
),
|
|
371
|
+
RegressionTestCase(
|
|
372
|
+
id="REG-SML-006",
|
|
373
|
+
category=DiagnosticCategory.CODE_SMELLS,
|
|
374
|
+
description="Deprecated pipes.quote() replaced with shlex.quote()",
|
|
375
|
+
broken_input="import pipes\ncmd = pipes.quote('my file.txt')\n",
|
|
376
|
+
expected_healed_substring="shlex.quote",
|
|
377
|
+
must_parse_ast=True,
|
|
378
|
+
),
|
|
379
|
+
RegressionTestCase(
|
|
380
|
+
id="REG-SML-007",
|
|
381
|
+
category=DiagnosticCategory.CODE_SMELLS,
|
|
382
|
+
description="Identity comparison 'is 5' repaired to equality '== 5'",
|
|
383
|
+
broken_input="if count is 5:\n notify()\n",
|
|
384
|
+
expected_healed_substring="if count == 5:",
|
|
385
|
+
must_parse_ast=True,
|
|
386
|
+
),
|
|
387
|
+
RegressionTestCase(
|
|
388
|
+
id="REG-SML-008",
|
|
389
|
+
category=DiagnosticCategory.CODE_SMELLS,
|
|
390
|
+
description="Redundant boolean comparison 'flag == True' simplified to 'flag'",
|
|
391
|
+
broken_input="if is_valid == True:\n proceed()\n",
|
|
392
|
+
expected_healed_substring="if is_valid:",
|
|
393
|
+
must_parse_ast=True,
|
|
394
|
+
),
|
|
395
|
+
|
|
396
|
+
# ---------------------------------------------------------------------
|
|
397
|
+
# 4. Zero-Leak Security Scenarios
|
|
398
|
+
# ---------------------------------------------------------------------
|
|
399
|
+
RegressionTestCase(
|
|
400
|
+
id="REG-SEC-001",
|
|
401
|
+
category=DiagnosticCategory.SECURITY_CREDENTIAL,
|
|
402
|
+
description="AWS Access Key ID detected and redacted",
|
|
403
|
+
broken_input="aws_key = '" + "AK" + "IAIOSFODNN7EXAMPLE'\n",
|
|
404
|
+
expected_healed_substring="os.environ.get('AWS_ACCESS_KEY_ID')",
|
|
405
|
+
must_not_contain="AK" + "IAIOSFODNN7EXAMPLE",
|
|
406
|
+
must_parse_ast=True,
|
|
407
|
+
),
|
|
408
|
+
RegressionTestCase(
|
|
409
|
+
id="REG-SEC-002",
|
|
410
|
+
category=DiagnosticCategory.SECURITY_CREDENTIAL,
|
|
411
|
+
description="GitHub Personal Access Token ghp_ detected and redacted",
|
|
412
|
+
broken_input="gh_token = '" + "gh" + "p_123456789012345678901234567890123456'\n",
|
|
413
|
+
expected_healed_substring="os.environ.get('GITHUB_TOKEN')",
|
|
414
|
+
must_not_contain="gh" + "p_123456789012345678901234567890123456",
|
|
415
|
+
must_parse_ast=True,
|
|
416
|
+
),
|
|
417
|
+
RegressionTestCase(
|
|
418
|
+
id="REG-SEC-003",
|
|
419
|
+
category=DiagnosticCategory.SECURITY_CREDENTIAL,
|
|
420
|
+
description="OpenAI API key sk-proj- detected and redacted",
|
|
421
|
+
broken_input="openai_api_key = '" + "s" + "k-proj-123456789012345678901234567890123456789012345678'\n",
|
|
422
|
+
expected_healed_substring="os.environ.get('OPENAI_API_KEY')",
|
|
423
|
+
must_not_contain="s" + "k-proj-12345678901234567890",
|
|
424
|
+
must_parse_ast=True,
|
|
425
|
+
),
|
|
426
|
+
RegressionTestCase(
|
|
427
|
+
id="REG-SEC-004",
|
|
428
|
+
category=DiagnosticCategory.SECURITY_CREDENTIAL,
|
|
429
|
+
description="Google AI Studio / Gemini API key AIzaSy detected and redacted",
|
|
430
|
+
broken_input="gemini_key = '" + "AI" + "zaSyA1b2C3d4A1b2C3d4A1b2C3d4A1b2C3d4A1'\n",
|
|
431
|
+
expected_healed_substring="os.environ.get('GEMINI_API_KEY')",
|
|
432
|
+
must_not_contain="AI" + "zaSyA1b2C3d4",
|
|
433
|
+
must_parse_ast=True,
|
|
434
|
+
),
|
|
435
|
+
RegressionTestCase(
|
|
436
|
+
id="REG-SEC-005",
|
|
437
|
+
category=DiagnosticCategory.SECURITY_CREDENTIAL,
|
|
438
|
+
description="Stripe secret key sk_live_ detected and redacted",
|
|
439
|
+
broken_input="stripe_secret = '" + "s" + "k_live_51AbcdEfgh12345678901234567890'\n",
|
|
440
|
+
expected_healed_substring="os.environ.get('STRIPE_SECRET_KEY')",
|
|
441
|
+
must_not_contain="s" + "k_live_51Abcd",
|
|
442
|
+
must_parse_ast=True,
|
|
443
|
+
),
|
|
444
|
+
|
|
445
|
+
# ---------------------------------------------------------------------
|
|
446
|
+
# 5. Polyglot Configuration & Build Scenarios
|
|
447
|
+
# ---------------------------------------------------------------------
|
|
448
|
+
RegressionTestCase(
|
|
449
|
+
id="REG-POL-001",
|
|
450
|
+
category=DiagnosticCategory.POLYGLOT_CONFIG,
|
|
451
|
+
description="JSON trailing comma repaired surgically",
|
|
452
|
+
broken_input='{\n "version": "1.0.0",\n "enabled": true,\n}\n',
|
|
453
|
+
expected_healed_substring='"enabled": true\n}',
|
|
454
|
+
must_not_contain='true,',
|
|
455
|
+
must_parse_ast=False,
|
|
456
|
+
),
|
|
457
|
+
RegressionTestCase(
|
|
458
|
+
id="REG-POL-002",
|
|
459
|
+
category=DiagnosticCategory.POLYGLOT_CONFIG,
|
|
460
|
+
description="JSON single quotes converted to double quotes",
|
|
461
|
+
broken_input="{\n 'name': 'tzero-project'\n}\n",
|
|
462
|
+
expected_healed_substring='"name": "tzero-project"',
|
|
463
|
+
must_parse_ast=False,
|
|
464
|
+
),
|
|
465
|
+
RegressionTestCase(
|
|
466
|
+
id="REG-POL-003",
|
|
467
|
+
category=DiagnosticCategory.POLYGLOT_CONFIG,
|
|
468
|
+
description="Makefile recipe spaces converted to hard TAB",
|
|
469
|
+
broken_input="build:\n cargo build --release\n",
|
|
470
|
+
expected_healed_substring="build:\n\tcargo build --release",
|
|
471
|
+
must_parse_ast=False,
|
|
472
|
+
),
|
|
473
|
+
RegressionTestCase(
|
|
474
|
+
id="REG-POL-004",
|
|
475
|
+
category=DiagnosticCategory.POLYGLOT_CONFIG,
|
|
476
|
+
description="Markdown unclosed code fence auto-closed",
|
|
477
|
+
broken_input="# Guide\n```python\nprint(1)\n",
|
|
478
|
+
expected_healed_substring="```python\nprint(1)\n```",
|
|
479
|
+
must_parse_ast=False,
|
|
480
|
+
),
|
|
481
|
+
RegressionTestCase(
|
|
482
|
+
id="REG-POL-005",
|
|
483
|
+
category=DiagnosticCategory.POLYGLOT_CONFIG,
|
|
484
|
+
description="Dockerfile ADD converted to COPY for local files",
|
|
485
|
+
broken_input="FROM alpine:3.18\nADD ./src /app/src\n",
|
|
486
|
+
expected_healed_substring="COPY ./src /app/src",
|
|
487
|
+
must_not_contain="ADD ./src",
|
|
488
|
+
must_parse_ast=False,
|
|
489
|
+
),
|
|
490
|
+
RegressionTestCase(
|
|
491
|
+
id="REG-POL-006",
|
|
492
|
+
category=DiagnosticCategory.POLYGLOT_CONFIG,
|
|
493
|
+
description="GitHub Actions deprecated checkout action upgraded to v4",
|
|
494
|
+
broken_input="- name: Checkout\n uses: actions/checkout@v2\n",
|
|
495
|
+
expected_healed_substring="actions/checkout@v4",
|
|
496
|
+
must_not_contain="actions/checkout@v2",
|
|
497
|
+
must_parse_ast=False,
|
|
498
|
+
),
|
|
499
|
+
RegressionTestCase(
|
|
500
|
+
id="REG-POL-007",
|
|
501
|
+
category=DiagnosticCategory.POLYGLOT_CONFIG,
|
|
502
|
+
description="pyproject.toml missing [build-system] table injected",
|
|
503
|
+
broken_input='[project]\nname = "my-lib"\nversion = "0.1.0"\n',
|
|
504
|
+
expected_healed_substring="[build-system]\nrequires =",
|
|
505
|
+
must_parse_ast=False,
|
|
506
|
+
),
|
|
507
|
+
]
|
|
508
|
+
|
|
509
|
+
@classmethod
|
|
510
|
+
def run_suite(cls) -> RegressionResult:
|
|
511
|
+
"""
|
|
512
|
+
Executes all scenarios, runs healers, checks assertions, and verifies AST parses.
|
|
513
|
+
"""
|
|
514
|
+
import time
|
|
515
|
+
|
|
516
|
+
start_time = time.time()
|
|
517
|
+
passed = 0
|
|
518
|
+
failed = 0
|
|
519
|
+
errors: List[str] = []
|
|
520
|
+
|
|
521
|
+
syntax_healer = ASTSyntaxHealer()
|
|
522
|
+
smells_healer = CodeSmellsHealer()
|
|
523
|
+
type_modernizer = ASTTypeModernizer()
|
|
524
|
+
security_doctor = SecurityZeroLeakDoctor()
|
|
525
|
+
|
|
526
|
+
for case in cls.SCENARIOS:
|
|
527
|
+
try:
|
|
528
|
+
healed_content = case.broken_input
|
|
529
|
+
|
|
530
|
+
# Route to appropriate healer
|
|
531
|
+
if case.category == DiagnosticCategory.PYTHON_SYNTAX:
|
|
532
|
+
res = syntax_healer.heal_string(case.broken_input, filename=f"{case.id}.py")
|
|
533
|
+
healed_content = res.repaired_content
|
|
534
|
+
|
|
535
|
+
elif case.category == DiagnosticCategory.CODE_SMELLS:
|
|
536
|
+
if "typing." in case.broken_input or "Optional[" in case.broken_input or "Union[" in case.broken_input or "@dataclass" in case.broken_input:
|
|
537
|
+
res = type_modernizer.modernize_code(case.broken_input)
|
|
538
|
+
healed_content = res.repaired_content
|
|
539
|
+
else:
|
|
540
|
+
res = smells_healer.heal_code_smells(case.broken_input)
|
|
541
|
+
healed_content = res.repaired_content
|
|
542
|
+
|
|
543
|
+
elif case.category == DiagnosticCategory.SECURITY_CREDENTIAL:
|
|
544
|
+
res = security_doctor.sanitize_string(case.broken_input)
|
|
545
|
+
healed_content = res.repaired_content
|
|
546
|
+
|
|
547
|
+
elif case.category == DiagnosticCategory.POLYGLOT_CONFIG:
|
|
548
|
+
if case.id == "REG-POL-001" or case.id == "REG-POL-002":
|
|
549
|
+
res = PolyglotConfigHealer.heal_json_string(case.broken_input)
|
|
550
|
+
healed_content = res.repaired_content
|
|
551
|
+
elif case.id == "REG-POL-003":
|
|
552
|
+
res = MakefileLinterHealer.lint_and_heal("Makefile", case.broken_input)
|
|
553
|
+
healed_content = res.repaired_content
|
|
554
|
+
elif case.id == "REG-POL-004":
|
|
555
|
+
res = MarkdownLinterHealer.lint_and_heal("README.md", case.broken_input)
|
|
556
|
+
healed_content = res.repaired_content
|
|
557
|
+
elif case.id == "REG-POL-005":
|
|
558
|
+
res = DockerfileDeepLinterHealer.lint_and_heal("Dockerfile", case.broken_input)
|
|
559
|
+
healed_content = res.repaired_content
|
|
560
|
+
elif case.id == "REG-POL-006":
|
|
561
|
+
res = YamlCiCdLinterHealer.lint_and_heal(".github/workflows/ci.yml", case.broken_input)
|
|
562
|
+
healed_content = res.repaired_content
|
|
563
|
+
elif case.id == "REG-POL-007":
|
|
564
|
+
res = TomlLinterHealer.lint_and_heal("pyproject.toml", case.broken_input)
|
|
565
|
+
healed_content = res.repaired_content
|
|
566
|
+
|
|
567
|
+
# Verify expected substring exists
|
|
568
|
+
if case.expected_healed_substring not in healed_content:
|
|
569
|
+
raise AssertionError(
|
|
570
|
+
f"Expected substring '{case.expected_healed_substring}' not in healed output: {healed_content!r}"
|
|
571
|
+
)
|
|
572
|
+
|
|
573
|
+
# Verify must_not_contain if defined
|
|
574
|
+
if case.must_not_contain and case.must_not_contain in healed_content:
|
|
575
|
+
raise AssertionError(
|
|
576
|
+
f"Forbidden substring '{case.must_not_contain}' still present in healed output."
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
# Verify AST parse if requested
|
|
580
|
+
if case.must_parse_ast:
|
|
581
|
+
try:
|
|
582
|
+
ast.parse(healed_content)
|
|
583
|
+
except SyntaxError as e:
|
|
584
|
+
raise AssertionError(f"Healed output failed to parse into valid Python AST: {e}\n{healed_content}")
|
|
585
|
+
|
|
586
|
+
passed += 1
|
|
587
|
+
|
|
588
|
+
except Exception as ex:
|
|
589
|
+
failed += 1
|
|
590
|
+
errors.append(f"[{case.id}] {case.description}: {ex}")
|
|
591
|
+
|
|
592
|
+
elapsed_ms = (time.time() - start_time) * 1000.0
|
|
593
|
+
|
|
594
|
+
return RegressionResult(
|
|
595
|
+
total_cases=len(cls.SCENARIOS),
|
|
596
|
+
passed_cases=passed,
|
|
597
|
+
failed_cases=failed,
|
|
598
|
+
errors=errors,
|
|
599
|
+
execution_time_ms=elapsed_ms,
|
|
600
|
+
)
|