tzero-mcp 10.7.0 → 10.7.1

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 (96) hide show
  1. package/bin/tzero-mcp.js +9 -16
  2. package/bin/tzero.js +9 -16
  3. package/index.js +7 -2
  4. package/package.json +2 -1
  5. package/src/addmcp.py +1194 -0
  6. package/src/main.py +60 -0
  7. package/src/siber_akademi_icon.py +77 -0
  8. package/src/tzero/jarvis/semantic_compressor.py +373 -0
  9. package/src/tzero.py +58 -0
  10. package/src/tzero_benchmark.py +475 -0
  11. package/src/tzero_bridge.py +362 -0
  12. package/src/tzero_ci.py +153 -0
  13. package/src/tzero_commit.py +192 -0
  14. package/src/tzero_cost.py +163 -0
  15. package/src/tzero_dashboard.py +1448 -0
  16. package/src/tzero_deps.py +287 -0
  17. package/src/tzero_drift.py +208 -0
  18. package/src/tzero_explain.py +240 -0
  19. package/src/tzero_features.py +3022 -0
  20. package/src/tzero_fix.py +228 -0
  21. package/src/tzero_fixer/__init__.py +63 -0
  22. package/src/tzero_fixer/amalgamation.py +334 -0
  23. package/src/tzero_fixer/ast_syntax_healer.py +464 -0
  24. package/src/tzero_fixer/ast_type_modernizer.py +288 -0
  25. package/src/tzero_fixer/async_io_modernizer.py +127 -0
  26. package/src/tzero_fixer/automated_regression_suite.py +600 -0
  27. package/src/tzero_fixer/benchmarks_and_diagnostics.py +174 -0
  28. package/src/tzero_fixer/ci_cd_self_healing_gate.py +246 -0
  29. package/src/tzero_fixer/code_duplicity_and_refactorer.py +151 -0
  30. package/src/tzero_fixer/code_smells_healer.py +260 -0
  31. package/src/tzero_fixer/cwe_remediator.py +171 -0
  32. package/src/tzero_fixer/dead_code_eliminator.py +150 -0
  33. package/src/tzero_fixer/dependency_vulnerability_auditor.py +309 -0
  34. package/src/tzero_fixer/git_advanced_surgeon.py +280 -0
  35. package/src/tzero_fixer/hardware_and_disk_doctor.py +325 -0
  36. package/src/tzero_fixer/import_graph_healer.py +412 -0
  37. package/src/tzero_fixer/interactive_tui.py +91 -0
  38. package/src/tzero_fixer/knowledge_base.py +295 -0
  39. package/src/tzero_fixer/knowledge_base_extended.py +940 -0
  40. package/src/tzero_fixer/linters_and_static_analyzer.py +307 -0
  41. package/src/tzero_fixer/mcp_server.py +447 -0
  42. package/src/tzero_fixer/models.py +385 -0
  43. package/src/tzero_fixer/orchestrator.py +375 -0
  44. package/src/tzero_fixer/os_doctor.py +502 -0
  45. package/src/tzero_fixer/packaging_abi_surgeon.py +323 -0
  46. package/src/tzero_fixer/pc_fixer_doctor.py +599 -0
  47. package/src/tzero_fixer/performance_and_memory_profiler.py +274 -0
  48. package/src/tzero_fixer/polyglot_ast_parsers.py +313 -0
  49. package/src/tzero_fixer/polyglot_build_healer.py +364 -0
  50. package/src/tzero_fixer/polyglot_config_healer.py +318 -0
  51. package/src/tzero_fixer/polyglot_doctor.py +372 -0
  52. package/src/tzero_fixer/polyglot_linters.py +619 -0
  53. package/src/tzero_fixer/polyglot_schema_validator.py +305 -0
  54. package/src/tzero_fixer/security_cwe_database.py +444 -0
  55. package/src/tzero_fixer/security_deep_rules.py +114 -0
  56. package/src/tzero_fixer/security_rules_catalog.py +110 -0
  57. package/src/tzero_fixer/security_zero_leak.py +326 -0
  58. package/src/tzero_fixer/smart_patch_recommender.py +223 -0
  59. package/src/tzero_fixer/synthetic_workspace_generator.py +220 -0
  60. package/src/tzero_fixer/system_diagnostics_extended.py +493 -0
  61. package/src/tzero_fixer/system_repair_recipes.py +447 -0
  62. package/src/tzero_fixer/venv_doctor.py +309 -0
  63. package/src/tzero_gateway.py +885 -0
  64. package/src/tzero_guard.py +243 -0
  65. package/src/tzero_infra.py +274 -0
  66. package/src/tzero_jarvis/__init__.py +124 -0
  67. package/src/tzero_jarvis/causal_graph.py +310 -0
  68. package/src/tzero_jarvis/graph_visualizer.py +395 -0
  69. package/src/tzero_jarvis/hybrid_search.py +214 -0
  70. package/src/tzero_jarvis/latent_press.py +137 -0
  71. package/src/tzero_jarvis/memory_consolidation.py +212 -0
  72. package/src/tzero_jarvis/minhash_lsh.py +184 -0
  73. package/src/tzero_jarvis/orchestrator.py +335 -0
  74. package/src/tzero_jarvis/self_healing.py +308 -0
  75. package/src/tzero_jarvis/semantic_compressor.py +887 -0
  76. package/src/tzero_jarvis/swarm.py +261 -0
  77. package/src/tzero_jarvis/swarm_bft.py +144 -0
  78. package/src/tzero_jarvis/workspace_orchestrator.py +1167 -0
  79. package/src/tzero_jarvis/zero_key_router.py +173 -0
  80. package/src/tzero_mcp.py +4858 -0
  81. package/src/tzero_neural_cortex.py +1425 -0
  82. package/src/tzero_packer.py +370 -0
  83. package/src/tzero_patch.py +624 -0
  84. package/src/tzero_pc_fixer.py +12657 -0
  85. package/src/tzero_pipe.py +95 -0
  86. package/src/tzero_polyglot.py +422 -0
  87. package/src/tzero_reachability.py +272 -0
  88. package/src/tzero_replay.py +141 -0
  89. package/src/tzero_security.py +570 -0
  90. package/src/tzero_snapshot.py +258 -0
  91. package/src/tzero_stubs.py +313 -0
  92. package/src/tzero_superdesign.py +774 -0
  93. package/src/tzero_sync.py +241 -0
  94. package/src/tzero_task_benchmark.py +363 -0
  95. package/src/tzero_tui.py +244 -0
  96. package/src/tzero_v3.py +9435 -0
@@ -0,0 +1,570 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Siber Akademi — T-Zero 100% Zero-Leak Security & Shannon Entropy Engine.
4
+ Developer: Toprak Ahmet Aydoğmuş (Siber Akademi)
5
+ License: MIT
6
+
7
+ Centralized, high-throughput offline security engine providing:
8
+ 1. Signature-based secret scanning across 20+ cloud, AI, payment, and VCS providers.
9
+ 2. Shannon Entropy mathematical anomaly detection for raw un-prefixed cryptographic keys.
10
+ 3. AST-level and textual Zero-Leak secret redaction ([ZERO_LEAK_MASKED_...]).
11
+ 4. Git pre-commit, MCP, and CLI verification integrations.
12
+ """
13
+
14
+ import math
15
+ import os
16
+ import re
17
+ import ast
18
+ from collections import Counter
19
+ from dataclasses import dataclass, field
20
+ from typing import Dict, List, Tuple, Optional, Any, Set
21
+
22
+
23
+ # ==============================================================================
24
+ # 1. SHANNON ENTROPY DETECTOR
25
+ # ==============================================================================
26
+
27
+ def calculate_shannon_entropy(data: str) -> float:
28
+ """Calculates Shannon entropy (bits per symbol) of a given string.
29
+
30
+ Higher entropy indicates higher randomness (e.g. cryptographic keys,
31
+ base64-encoded secrets, high-entropy tokens).
32
+ Standard English text: ~2.5 - 3.5
33
+ Source code identifiers: ~3.0 - 3.8
34
+ Random Base64 / Hex secrets (32+ chars): ~4.5 - 6.0
35
+ """
36
+ if not data:
37
+ return 0.0
38
+ length = len(data)
39
+ counts = Counter(data)
40
+ entropy = 0.0
41
+ for count in counts.values():
42
+ p = count / length
43
+ entropy -= p * math.log2(p)
44
+ return entropy
45
+
46
+
47
+ # Ignore words and markers that produce high false positives
48
+ COMMON_ENTROPY_WHITELIST = {
49
+ "undefined", "constructor", "classmethod", "staticmethod", "authorization",
50
+ "content-type", "application/json", "multipart/form-data", "x-www-form-urlencoded",
51
+ "abcdefghijklmnopqrstuvwxyz", "0123456789abcdef", "placeholder", "your_secret_here"
52
+ }
53
+
54
+ PLACEHOLDER_SUBSTRINGS = (
55
+ "YOUR_API_KEY", "YOUR-API-KEY", "YOUR_SECRET", "YOUR_TOKEN",
56
+ "YOUR-", "YOUR_", "ENTER_YOUR", "PLACEHOLDER", "CHANGEME", "INSERT_HERE",
57
+ "000000000000", "EXAMPLE_KEY", "EXAMPLEKEY", "EXAMPLE_SECRET",
58
+ "MOCK_KEY_PLACEHOLDER", "MOCK", "DEMO"
59
+ )
60
+
61
+
62
+ # ==============================================================================
63
+ # 2. COMPREHENSIVE SECRET SIGNATURE DATABASE
64
+ # ==============================================================================
65
+
66
+ @dataclass
67
+ class SecretRule:
68
+ rule_id: str
69
+ provider: str
70
+ description: str
71
+ pattern: re.Pattern
72
+ severity: str = "CRITICAL"
73
+ mask_tag: str = "[ZERO_LEAK_MASKED_SECRET]"
74
+
75
+
76
+ SECRET_RULES: List[SecretRule] = [
77
+ # --- AI & Cloud Providers ---
78
+ SecretRule(
79
+ rule_id="SEC-AI-002",
80
+ provider="Anthropic",
81
+ description="Anthropic Claude API Key (sk-ant-...)",
82
+ pattern=re.compile(r"\b(sk-ant-[a-zA-Z0-9_\-]{30,})\b"),
83
+ mask_tag="[ZERO_LEAK_MASKED_ANTHROPIC_KEY]"
84
+ ),
85
+ SecretRule(
86
+ rule_id="SEC-AI-001",
87
+ provider="OpenAI",
88
+ description="OpenAI API Key (sk-...)",
89
+ pattern=re.compile(r"\b(sk-(?!ant-)[a-zA-Z0-9_\-]{20,})\b"),
90
+ mask_tag="[ZERO_LEAK_MASKED_OPENAI_KEY]"
91
+ ),
92
+ SecretRule(
93
+ rule_id="SEC-AI-003",
94
+ provider="Google",
95
+ description="Google Cloud / Gemini API Key (AIza...)",
96
+ pattern=re.compile(r"\b(AIza[0-9A-Za-z\-_]{30,45})\b"),
97
+ mask_tag="[ZERO_LEAK_MASKED_GEMINI_KEY]"
98
+ ),
99
+ SecretRule(
100
+ rule_id="SEC-AI-004",
101
+ provider="HuggingFace",
102
+ description="HuggingFace User Access Token (hf_...)",
103
+ pattern=re.compile(r"\b(hf_[a-zA-Z0-9]{34,})\b"),
104
+ mask_tag="[ZERO_LEAK_MASKED_HF_TOKEN]"
105
+ ),
106
+ SecretRule(
107
+ rule_id="SEC-AI-005",
108
+ provider="NVIDIA",
109
+ description="NVIDIA NIM API Key (nvapi-...)",
110
+ pattern=re.compile(r"\b(nvapi-[a-zA-Z0-9_\-]{30,})\b"),
111
+ mask_tag="[ZERO_LEAK_MASKED_NVIDIA_KEY]"
112
+ ),
113
+ SecretRule(
114
+ rule_id="SEC-AI-006",
115
+ provider="Groq",
116
+ description="Groq Cloud API Key (gsk_...)",
117
+ pattern=re.compile(r"\b(gsk_[a-zA-Z0-9]{48,})\b"),
118
+ mask_tag="[ZERO_LEAK_MASKED_GROQ_KEY]"
119
+ ),
120
+ SecretRule(
121
+ rule_id="SEC-AI-007",
122
+ provider="OpenRouter",
123
+ description="OpenRouter API Key (sk-or-v1-...)",
124
+ pattern=re.compile(r"\b(sk-or-v1-[a-f0-9]{64})\b"),
125
+ mask_tag="[ZERO_LEAK_MASKED_OPENROUTER_KEY]"
126
+ ),
127
+ SecretRule(
128
+ rule_id="SEC-AI-008",
129
+ provider="Perplexity",
130
+ description="Perplexity AI API Key (pplx-...)",
131
+ pattern=re.compile(r"\b(pplx-[a-zA-Z0-9]{48,})\b"),
132
+ mask_tag="[ZERO_LEAK_MASKED_PERPLEXITY_KEY]"
133
+ ),
134
+ SecretRule(
135
+ rule_id="SEC-AI-009",
136
+ provider="Replicate",
137
+ description="Replicate API Token (r8_...)",
138
+ pattern=re.compile(r"\b(r8_[a-zA-Z0-9]{32,})\b"),
139
+ mask_tag="[ZERO_LEAK_MASKED_REPLICATE_KEY]"
140
+ ),
141
+ SecretRule(
142
+ rule_id="SEC-AI-010",
143
+ provider="Cohere",
144
+ description="Cohere API Key (co-...)",
145
+ pattern=re.compile(r"\b(co-[a-zA-Z0-9]{40,})\b"),
146
+ mask_tag="[ZERO_LEAK_MASKED_COHERE_KEY]"
147
+ ),
148
+ SecretRule(
149
+ rule_id="SEC-REG-001",
150
+ provider="NPM",
151
+ description="NPM Registry Access Token (npm_...)",
152
+ pattern=re.compile(r"\b(npm_[a-zA-Z0-9]{32,40})\b"),
153
+ mask_tag="[ZERO_LEAK_MASKED_NPM_TOKEN]"
154
+ ),
155
+
156
+ # --- Cloud Infrastructure & VCS ---
157
+ SecretRule(
158
+ rule_id="SEC-AWS-001",
159
+ provider="AWS",
160
+ description="AWS Access Key ID (AKIA...)",
161
+ pattern=re.compile(r"\b(AKIA[0-9A-Z]{16})\b"),
162
+ mask_tag="[ZERO_LEAK_MASKED_AWS_KEY]"
163
+ ),
164
+ SecretRule(
165
+ rule_id="SEC-AWS-002",
166
+ provider="AWS",
167
+ description="AWS Secret Access Key",
168
+ pattern=re.compile(r"(?i)aws_secret_access_key\s*[:=]\s*['\"]([0-9a-zA-Z/+]{40})['\"]"),
169
+ mask_tag="[ZERO_LEAK_MASKED_AWS_SECRET]"
170
+ ),
171
+ SecretRule(
172
+ rule_id="SEC-GH-001",
173
+ provider="GitHub",
174
+ description="GitHub Personal Access Token (Classic: ghp_...)",
175
+ pattern=re.compile(r"\b(ghp_[a-zA-Z0-9]{36})\b"),
176
+ mask_tag="[ZERO_LEAK_MASKED_GITHUB_PAT]"
177
+ ),
178
+ SecretRule(
179
+ rule_id="SEC-GH-002",
180
+ provider="GitHub",
181
+ description="GitHub OAuth Token (gho_...)",
182
+ pattern=re.compile(r"\b(gho_[a-zA-Z0-9]{36})\b"),
183
+ mask_tag="[ZERO_LEAK_MASKED_GITHUB_OAUTH]"
184
+ ),
185
+ SecretRule(
186
+ rule_id="SEC-GH-003",
187
+ provider="GitHub",
188
+ description="GitHub Fine-Grained Personal Access Token (github_pat_...)",
189
+ pattern=re.compile(r"\b(github_pat_[a-zA-Z0-9_]{50,})\b"),
190
+ mask_tag="[ZERO_LEAK_MASKED_GITHUB_FINE_PAT]"
191
+ ),
192
+ SecretRule(
193
+ rule_id="SEC-SLACK-001",
194
+ provider="Slack",
195
+ description="Slack Bot/User Token (xoxb/xoxp-...)",
196
+ pattern=re.compile(r"\b(xox[baprs]-(?:[0-9a-zA-Z]{9,}-)+[a-zA-Z0-9]{20,})\b"),
197
+ mask_tag="[ZERO_LEAK_MASKED_SLACK_TOKEN]"
198
+ ),
199
+ SecretRule(
200
+ rule_id="SEC-STRIPE-001",
201
+ provider="Stripe",
202
+ description="Stripe Live Secret Key (sk_live_...)",
203
+ pattern=re.compile(r"\b((?:sk|rk)_live_[0-9a-zA-Z]{24,})\b"),
204
+ mask_tag="[ZERO_LEAK_MASKED_STRIPE_KEY]"
205
+ ),
206
+
207
+ # --- Cryptographic & Auth Artifacts ---
208
+ SecretRule(
209
+ rule_id="SEC-CRYPTO-001",
210
+ provider="PKI",
211
+ description="Private Key Header (RSA, EC, OPENSSH, DSA, PGP)",
212
+ pattern=re.compile(r"-----BEGIN (?:RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----"),
213
+ mask_tag="[ZERO_LEAK_MASKED_PRIVATE_KEY]"
214
+ ),
215
+ SecretRule(
216
+ rule_id="SEC-AUTH-001",
217
+ provider="JWT",
218
+ description="JSON Web Token (JWT Header + Payload + Signature)",
219
+ pattern=re.compile(r"\b(eyJ[a-zA-Z0-9_\-]{10,}\.eyJ[a-zA-Z0-9_\-]{10,}\.[a-zA-Z0-9_\-]{10,})\b"),
220
+ mask_tag="[ZERO_LEAK_MASKED_JWT]"
221
+ ),
222
+ SecretRule(
223
+ rule_id="SEC-AUTH-002",
224
+ provider="HTTP",
225
+ description="Bearer Authorization Token Header",
226
+ pattern=re.compile(r"(?i)Bearer\s+([a-zA-Z0-9_\.\-]{24,})"),
227
+ mask_tag="Bearer [ZERO_LEAK_MASKED_TOKEN]"
228
+ ),
229
+ SecretRule(
230
+ rule_id="SEC-DB-001",
231
+ provider="Database",
232
+ description="Database Connection URI with Credentials",
233
+ pattern=re.compile(r"(?:postgres|postgresql|mysql|mongodb(?:\+srv)?|redis)://[^:\s]+:[^@\s]+@[^\s\"']+"),
234
+ mask_tag="[ZERO_LEAK_MASKED_DB_URL]"
235
+ ),
236
+ SecretRule(
237
+ rule_id="SEC-GENERIC-001",
238
+ provider="Generic",
239
+ description="Hardcoded Secret Assignment (api_key/secret/password)",
240
+ pattern=re.compile(r"""(?i)(?:api_?key|secret_?key|app_?secret|db_?pass(?:word)?|auth_?token)\s*[:=]\s*['"]([^'"]{12,})['"]"""),
241
+ mask_tag="[ZERO_LEAK_MASKED_VALUE]"
242
+ ),
243
+ ]
244
+
245
+
246
+ # ==============================================================================
247
+ # 3. DETECTION & SCANNING INTERFACES
248
+ # ==============================================================================
249
+
250
+ @dataclass
251
+ class SecretFinding:
252
+ rule_id: str
253
+ provider: str
254
+ description: str
255
+ severity: str
256
+ line_no: int
257
+ preview: str
258
+ entropy: float = 0.0
259
+ is_entropy_anomaly: bool = False
260
+ secret_value: str = ""
261
+
262
+
263
+ class ZeroLeakEngine:
264
+ """Enterprise 100% Zero-Leak security scanner and sanitizer."""
265
+
266
+ MIN_ENTROPY_THRESHOLD: float = 4.75
267
+ MIN_ENTROPY_LENGTH: int = 28
268
+
269
+ @classmethod
270
+ def is_placeholder(cls, s: str) -> bool:
271
+ """Determines if a candidate string is an intentional placeholder/mock."""
272
+ up = s.upper()
273
+ return any(ph in up for ph in PLACEHOLDER_SUBSTRINGS)
274
+
275
+ @classmethod
276
+ def is_natural_or_identifier(cls, s: str) -> bool:
277
+ """Rejects common false positives (all-lowercase slugs, public project/team IDs)."""
278
+ # Exclude public identifiers
279
+ if s.startswith(("prj_", "team_", "col_", "tbl_", "usr_", "pkg_", "sub_")):
280
+ return True
281
+ # Natural language smushed slugs without variety
282
+ if s.islower() or s.isupper():
283
+ return True
284
+ # Check character class diversity (needs at least uppercase, lowercase, and digit/special)
285
+ has_upper = any(c.isupper() for c in s)
286
+ has_lower = any(c.islower() for c in s)
287
+ has_digit = any(c.isdigit() for c in s)
288
+ has_punct = any(not c.isalnum() for c in s)
289
+ diversity = sum([has_upper, has_lower, (has_digit or has_punct)])
290
+ return diversity < 2
291
+
292
+ @classmethod
293
+ def scan_text(cls, text: str, check_entropy: bool = True) -> List[SecretFinding]:
294
+ """Scans in-memory text for known secrets and high-entropy secret anomalies."""
295
+ if not text:
296
+ return []
297
+
298
+ findings: List[SecretFinding] = []
299
+ lines = text.splitlines()
300
+
301
+ for lineno, line in enumerate(lines, 1):
302
+ stripped = line.strip()
303
+ if not stripped or stripped.startswith(("#", "//", "*", "/*")):
304
+ continue
305
+
306
+ # 1. Signature Rule Matching
307
+ has_specific_provider_match = False
308
+ for rule in SECRET_RULES:
309
+ # If a specific provider rule matched, avoid duplicate generic rule hit on same line
310
+ if rule.rule_id == "SEC-GENERIC-001" and has_specific_provider_match:
311
+ continue
312
+
313
+ for match in rule.pattern.finditer(line):
314
+ val = match.group(0)
315
+ if cls.is_placeholder(val):
316
+ continue
317
+
318
+ ent = calculate_shannon_entropy(val)
319
+ findings.append(SecretFinding(
320
+ rule_id=rule.rule_id,
321
+ provider=rule.provider,
322
+ description=rule.description,
323
+ severity=rule.severity,
324
+ line_no=lineno,
325
+ preview=cls.mask_preview(line),
326
+ entropy=round(ent, 2),
327
+ is_entropy_anomaly=False,
328
+ secret_value=val
329
+ ))
330
+ if rule.provider != "Generic":
331
+ has_specific_provider_match = True
332
+
333
+ # 2. Shannon Entropy Scanner for Unmatched Candidate Tokens
334
+ if check_entropy:
335
+ # Candidate secrets must be single compact tokens without whitespace, slashes, or URL schemas
336
+ candidate_tokens = re.findall(r"""['"]([A-Za-z0-9+/=_\-]{28,})['"]""", line)
337
+ for tok in candidate_tokens:
338
+ # Filter out URLs, file paths, and common non-secrets
339
+ if any(prefix in tok for prefix in ("http:", "https:", "/", "\\", "@", ".com", ".org", ".net")):
340
+ continue
341
+ # Ignore SRI cryptographic package hashes and data URIs (e.g. package-lock.json integrity hashes)
342
+ if tok.startswith(("sha512-", "sha384-", "sha256-", "md5-", "urn:", "data:")):
343
+ continue
344
+ if any(kw in line.lower() for kw in ('"integrity"', '"resolved"', '"hash"', 'sha512-', 'sha256-')):
345
+ continue
346
+ if cls.is_placeholder(tok) or tok.lower() in COMMON_ENTROPY_WHITELIST:
347
+ continue
348
+ if cls.is_natural_or_identifier(tok):
349
+ continue
350
+
351
+ ent = calculate_shannon_entropy(tok)
352
+ if ent >= cls.MIN_ENTROPY_THRESHOLD and len(tok) >= cls.MIN_ENTROPY_LENGTH:
353
+ already_reported = any(f.line_no == lineno for f in findings)
354
+ if not already_reported:
355
+ findings.append(SecretFinding(
356
+ rule_id="SEC-ENTROPY-001",
357
+ provider="EntropyAnomaly",
358
+ description=f"High-Entropy Secret Candidate (Shannon H={ent:.2f} >= {cls.MIN_ENTROPY_THRESHOLD})",
359
+ severity="HIGH",
360
+ line_no=lineno,
361
+ preview=cls.mask_preview(line),
362
+ entropy=round(ent, 2),
363
+ is_entropy_anomaly=True,
364
+ secret_value=tok
365
+ ))
366
+
367
+ return findings
368
+
369
+ @classmethod
370
+ def mask_preview(cls, line: str, max_len: int = 70) -> str:
371
+ """Sanitizes line for safe terminal output and logging."""
372
+ sanitized = cls.sanitize_text(line)
373
+ if len(sanitized) > max_len:
374
+ return sanitized[:max_len] + "..."
375
+ return sanitized
376
+
377
+ @classmethod
378
+ def sanitize_text(cls, text: str) -> str:
379
+ """Sanitizes text by masking all detected secrets with Zero-Leak tokens."""
380
+ if not text:
381
+ return ""
382
+
383
+ sanitized = text
384
+
385
+ # 1. Mask specific patterns
386
+ for rule in SECRET_RULES:
387
+ def _replace_match(m):
388
+ full_val = m.group(0)
389
+ if cls.is_placeholder(full_val):
390
+ return full_val
391
+ return rule.mask_tag
392
+ sanitized = rule.pattern.sub(_replace_match, sanitized)
393
+
394
+ # 2. Mask high entropy quoted literals
395
+ def _replace_entropy(m):
396
+ token = m.group(1)
397
+ if not cls.is_placeholder(token) and calculate_shannon_entropy(token) >= 4.4:
398
+ return f'"{token[:4]}...[ZERO_LEAK_HIGH_ENTROPY_SECRET]"'
399
+ return m.group(0)
400
+
401
+ sanitized = re.sub(r"""['"]([^'"]{20,})['"]""", _replace_entropy, sanitized)
402
+ return sanitized
403
+
404
+ @classmethod
405
+ def sanitize_ast(cls, tree: ast.AST) -> ast.AST:
406
+ """Walks an AST tree and replaces hardcoded string literals containing secrets."""
407
+ for node in ast.walk(tree):
408
+ if isinstance(node, ast.Constant) and isinstance(node.value, str):
409
+ val = node.value
410
+ # Check if raw value itself or wrapped in quotes triggers detection
411
+ if cls.scan_text(f'val = "{val}"'):
412
+ node.value = cls.sanitize_text(val)
413
+ return tree
414
+
415
+ @classmethod
416
+ def scan_files_map(cls, files_map: Dict[str, str]) -> Dict[str, Any]:
417
+ """Scans in-memory files map {relative_path: file_content}."""
418
+ violations = []
419
+ files_with_violations = 0
420
+
421
+ for path, content in files_map.items():
422
+ findings = cls.scan_text(content)
423
+ if findings:
424
+ files_with_violations += 1
425
+ for f in findings:
426
+ violations.append({
427
+ "file": path,
428
+ "line": f.line_no,
429
+ "type": f.description,
430
+ "provider": f.provider,
431
+ "severity": f.severity,
432
+ "preview": f.preview,
433
+ "entropy": f.entropy
434
+ })
435
+
436
+ return {
437
+ "clean": len(violations) == 0,
438
+ "violations": violations,
439
+ "violation_count": len(violations),
440
+ "files_scanned": len(files_map),
441
+ "files_with_violations": files_with_violations,
442
+ "status": "100% ZERO-LEAK VERIFIED" if not violations else "PROHIBITED CREDENTIALS DETECTED"
443
+ }
444
+
445
+ @classmethod
446
+ def scan_workspace(cls, workspace_dir: str = ".") -> dict:
447
+ """Scans a workspace directory for any hardcoded secrets and returns violations dict."""
448
+ files_map = {}
449
+ for root, dirs, files in os.walk(workspace_dir):
450
+ dirs[:] = [d for d in dirs if not d.startswith(".") and d not in ("__pycache__", "venv", ".venv", "node_modules", "dist", "build", ".git")]
451
+ for f in files:
452
+ if f.endswith((".py", ".js", ".ts", ".json", ".yaml", ".yml", ".env.example", ".sh", ".toml", ".txt")):
453
+ fp = os.path.join(root, f)
454
+ try:
455
+ with open(fp, "r", encoding="utf-8", errors="ignore") as fh:
456
+ files_map[fp] = fh.read()
457
+ except Exception:
458
+ pass
459
+ return cls.scan_files_map(files_map)
460
+
461
+ @classmethod
462
+ def auto_migrate_to_env(
463
+ cls,
464
+ code_str: str,
465
+ env_file_path: Optional[str] = None,
466
+ gitignore_path: Optional[str] = None
467
+ ) -> Tuple[str, str, int, str]:
468
+ """Automatically extracts detected hardcoded secrets into .env format and refactors code with os.environ.get."""
469
+ findings = cls.scan_text(code_str)
470
+ valid_findings = [f for f in findings if f.secret_value and not cls.is_placeholder(f.secret_value)]
471
+
472
+ if not valid_findings:
473
+ return code_str, "# No secrets detected.", 0, "### 100% Zero-Leak Certified\nNo hardcoded credentials found in source code."
474
+
475
+ migrated_code = code_str
476
+ env_entries: Dict[str, str] = {}
477
+ used_vars: Set[str] = set()
478
+ counter = 1
479
+
480
+ # Sort findings descending by length to avoid partial substrings
481
+ unique_findings = []
482
+ seen_vals = set()
483
+ for f in valid_findings:
484
+ if f.secret_value not in seen_vals:
485
+ seen_vals.add(f.secret_value)
486
+ unique_findings.append(f)
487
+ unique_findings.sort(key=lambda x: len(x.secret_value), reverse=True)
488
+
489
+ provider_map = {
490
+ "OpenAI": "OPENAI_API_KEY",
491
+ "Anthropic": "ANTHROPIC_API_KEY",
492
+ "Google": "GEMINI_API_KEY",
493
+ "HuggingFace": "HF_TOKEN",
494
+ "NVIDIA": "NVIDIA_API_KEY",
495
+ "AWS": "AWS_SECRET_ACCESS_KEY",
496
+ "GitHub": "GITHUB_TOKEN",
497
+ "GitLab": "GITLAB_TOKEN",
498
+ "Stripe": "STRIPE_SECRET_KEY",
499
+ "Slack": "SLACK_BOT_TOKEN",
500
+ "Database": "DATABASE_URL",
501
+ "JWT": "JWT_SECRET_TOKEN",
502
+ "PrivateKey": "PRIVATE_KEY_PEM",
503
+ }
504
+
505
+ report_lines = [
506
+ "### T-Zero Zero-Leak Auto-Vault Migration",
507
+ f"Extracted and secured **{len(unique_findings)}** hardcoded secret(s) into environment configuration:\n",
508
+ "| Provider | Variable Assigned | Redacted Secret |",
509
+ "| :--- | :--- | :--- |",
510
+ ]
511
+
512
+ for f in unique_findings:
513
+ base_var = provider_map.get(f.provider, "")
514
+ if not base_var:
515
+ clean_desc = re.sub(r"[^A-Z0-9_]", "_", f.description.upper()[:20])
516
+ base_var = f"{clean_desc}_TOKEN"
517
+
518
+ var_name = base_var
519
+ while var_name in used_vars:
520
+ var_name = f"{base_var}_{counter}"
521
+ counter += 1
522
+ used_vars.add(var_name)
523
+
524
+ env_entries[var_name] = f.secret_value
525
+ redacted = f.secret_value[:6] + "..." + f.secret_value[-4:] if len(f.secret_value) > 12 else "***"
526
+ report_lines.append(f"| `{f.provider}` | `{var_name}` | `{redacted}` |")
527
+
528
+ # Replace quotes in code
529
+ pat_d = f'"{f.secret_value}"'
530
+ pat_s = f"'{f.secret_value}'"
531
+ replacement = f'os.environ.get("{var_name}", "")'
532
+ if pat_d in migrated_code:
533
+ migrated_code = migrated_code.replace(pat_d, replacement)
534
+ elif pat_s in migrated_code:
535
+ migrated_code = migrated_code.replace(pat_s, replacement)
536
+ else:
537
+ migrated_code = migrated_code.replace(f.secret_value, replacement)
538
+
539
+ # Check if os is imported
540
+ if "os.environ" in migrated_code and "import os" not in migrated_code and "from os import" not in migrated_code:
541
+ migrated_code = "import os\n" + migrated_code
542
+
543
+ # Build .env text
544
+ env_lines = ["# Auto-Vault Generated by T-Zero Zero-Leak Engine", "# DO NOT COMMIT THIS FILE TO PUBLIC REPOSITORIES", ""]
545
+ for k, v in env_entries.items():
546
+ env_lines.append(f"{k}={v}")
547
+ env_content = "\n".join(env_lines) + "\n"
548
+
549
+ # If file paths provided, update physical .env and .gitignore
550
+ if env_file_path:
551
+ try:
552
+ with open(env_file_path, "a", encoding="utf-8") as ef:
553
+ ef.write("\n" + "\n".join(f"{k}={v}" for k, v in env_entries.items()) + "\n")
554
+ except Exception:
555
+ pass
556
+
557
+ if gitignore_path:
558
+ try:
559
+ gi_content = ""
560
+ if os.path.exists(gitignore_path):
561
+ with open(gitignore_path, "r", encoding="utf-8") as gf:
562
+ gi_content = gf.read()
563
+ if ".env" not in gi_content:
564
+ with open(gitignore_path, "a", encoding="utf-8") as gf:
565
+ gf.write("\n.env\n*.env\n")
566
+ except Exception:
567
+ pass
568
+
569
+ return migrated_code, env_content, len(unique_findings), "\n".join(report_lines)
570
+