patchi 0.7.5__py3-none-any.whl

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 (496) hide show
  1. patchi/__init__.py +1 -0
  2. patchi/__main__.py +13 -0
  3. patchi/cli/__init__.py +0 -0
  4. patchi/cli/command_families.py +235 -0
  5. patchi/cli/commands/__init__.py +0 -0
  6. patchi/cli/commands/access_cmd.py +65 -0
  7. patchi/cli/commands/agent_stats_cmd.py +273 -0
  8. patchi/cli/commands/agents_cmd.py +187 -0
  9. patchi/cli/commands/ai_cmd.py +308 -0
  10. patchi/cli/commands/assure_cmd.py +538 -0
  11. patchi/cli/commands/audit_cmd.py +286 -0
  12. patchi/cli/commands/auto_cmd.py +110 -0
  13. patchi/cli/commands/blame_cmd.py +53 -0
  14. patchi/cli/commands/chains_cmd.py +327 -0
  15. patchi/cli/commands/charter_cmd.py +173 -0
  16. patchi/cli/commands/chat_cmd.py +597 -0
  17. patchi/cli/commands/check_cmd.py +232 -0
  18. patchi/cli/commands/cleanup_cmd.py +328 -0
  19. patchi/cli/commands/cockpit_cmd.py +208 -0
  20. patchi/cli/commands/commands_cmd.py +160 -0
  21. patchi/cli/commands/cross_repo_cmd.py +113 -0
  22. patchi/cli/commands/deps_cmd.py +110 -0
  23. patchi/cli/commands/dev_check_cmd.py +342 -0
  24. patchi/cli/commands/dev_cmd.py +445 -0
  25. patchi/cli/commands/doctor_cmd.py +457 -0
  26. patchi/cli/commands/findings_cmd.py +187 -0
  27. patchi/cli/commands/fix_cmd.py +648 -0
  28. patchi/cli/commands/fix_review_cmd.py +273 -0
  29. patchi/cli/commands/heatmap_cmd.py +62 -0
  30. patchi/cli/commands/help_cmd.py +159 -0
  31. patchi/cli/commands/hosted_cmd.py +980 -0
  32. patchi/cli/commands/init.py +456 -0
  33. patchi/cli/commands/key_cmd.py +571 -0
  34. patchi/cli/commands/learn_cmd.py +140 -0
  35. patchi/cli/commands/link_cmd.py +104 -0
  36. patchi/cli/commands/log_cmd.py +57 -0
  37. patchi/cli/commands/memory_cmd.py +215 -0
  38. patchi/cli/commands/model_cmd.py +207 -0
  39. patchi/cli/commands/notify_cmd.py +213 -0
  40. patchi/cli/commands/notify_prompts.py +29 -0
  41. patchi/cli/commands/patch_cmd.py +231 -0
  42. patchi/cli/commands/plan_cmd.py +128 -0
  43. patchi/cli/commands/plugins_cmd.py +307 -0
  44. patchi/cli/commands/queue_cmd.py +152 -0
  45. patchi/cli/commands/quick_cmd.py +159 -0
  46. patchi/cli/commands/ready_cmd.py +292 -0
  47. patchi/cli/commands/report_cmd.py +416 -0
  48. patchi/cli/commands/restrict_cmd.py +127 -0
  49. patchi/cli/commands/review_cmd.py +225 -0
  50. patchi/cli/commands/rules_cmd.py +233 -0
  51. patchi/cli/commands/scan_cmd.py +1908 -0
  52. patchi/cli/commands/settings_cmd.py +45 -0
  53. patchi/cli/commands/status_cmd.py +679 -0
  54. patchi/cli/commands/test_cmd.py +1052 -0
  55. patchi/cli/commands/trend_cmd.py +296 -0
  56. patchi/cli/commands/undo_cmd.py +235 -0
  57. patchi/cli/commands/update_cmd.py +345 -0
  58. patchi/cli/commands/verify_cmd.py +56 -0
  59. patchi/cli/commands/vr_cmd.py +440 -0
  60. patchi/cli/commands/watch_cmd.py +304 -0
  61. patchi/cli/commands/web_cmd.py +114 -0
  62. patchi/cli/console.py +101 -0
  63. patchi/cli/display/__init__.py +1 -0
  64. patchi/cli/display/live_audit.py +269 -0
  65. patchi/cli/display/live_progress.py +169 -0
  66. patchi/cli/framework.py +241 -0
  67. patchi/cli/logo.py +128 -0
  68. patchi/cli/main.py +222 -0
  69. patchi/cli/registry.py +1171 -0
  70. patchi/cli/style.py +68 -0
  71. patchi/cli/themes.py +187 -0
  72. patchi/cli/ux.py +444 -0
  73. patchi/core/__init__.py +0 -0
  74. patchi/core/agents/__init__.py +0 -0
  75. patchi/core/agents/api_fuzzer_agent.py +141 -0
  76. patchi/core/agents/attack_agent.py +242 -0
  77. patchi/core/agents/base.py +1012 -0
  78. patchi/core/agents/bug_predictor_agent.py +58 -0
  79. patchi/core/agents/build_tool_validator.py +150 -0
  80. patchi/core/agents/cache.py +192 -0
  81. patchi/core/agents/chaos_agent.py +133 -0
  82. patchi/core/agents/cicd_generator.py +240 -0
  83. patchi/core/agents/comment_scanner.py +280 -0
  84. patchi/core/agents/console_logging_agent.py +156 -0
  85. patchi/core/agents/coordinator.py +858 -0
  86. patchi/core/agents/core_scanner.py +269 -0
  87. patchi/core/agents/coverage_prioritizer.py +181 -0
  88. patchi/core/agents/dead_code_hygiene.py +296 -0
  89. patchi/core/agents/dead_code_scanner.py +692 -0
  90. patchi/core/agents/dependency_scanner.py +725 -0
  91. patchi/core/agents/doc_claim_agent.py +573 -0
  92. patchi/core/agents/duplicate_scanner.py +568 -0
  93. patchi/core/agents/env_scanner.py +410 -0
  94. patchi/core/agents/feature_flag_agent.py +89 -0
  95. patchi/core/agents/frontend_framework_agent.py +133 -0
  96. patchi/core/agents/goroutine_agent.py +82 -0
  97. patchi/core/agents/governor.py +1972 -0
  98. patchi/core/agents/i18n_agent.py +95 -0
  99. patchi/core/agents/license_compliance.py +247 -0
  100. patchi/core/agents/linking_agent.py +251 -0
  101. patchi/core/agents/memory_profiler_agent.py +102 -0
  102. patchi/core/agents/modernization_agent.py +84 -0
  103. patchi/core/agents/mutation_agent.py +174 -0
  104. patchi/core/agents/nl_query_agent.py +74 -0
  105. patchi/core/agents/promise_rejection_agent.py +100 -0
  106. patchi/core/agents/refactoring_agent.py +286 -0
  107. patchi/core/agents/resource_leak_agent.py +91 -0
  108. patchi/core/agents/route_graph_scanner.py +951 -0
  109. patchi/core/agents/run_agent.py +106 -0
  110. patchi/core/agents/rust_unwrap_agent.py +100 -0
  111. patchi/core/agents/sbom_generator.py +284 -0
  112. patchi/core/agents/scanners.py +67 -0
  113. patchi/core/agents/side/__init__.py +1 -0
  114. patchi/core/agents/side/build_agent.py +65 -0
  115. patchi/core/agents/side/format_agent.py +50 -0
  116. patchi/core/agents/side/install_agent.py +63 -0
  117. patchi/core/agents/side_file_scanner.py +549 -0
  118. patchi/core/agents/snapshot_drift_detector.py +146 -0
  119. patchi/core/agents/spa_route_inventory.py +203 -0
  120. patchi/core/agents/test_scanner.py +442 -0
  121. patchi/core/agents/tool_health.py +109 -0
  122. patchi/core/agents/tool_runner.py +162 -0
  123. patchi/core/agents/type_scanner.py +168 -0
  124. patchi/core/agents/ui_scanner.py +558 -0
  125. patchi/core/ai/__init__.py +20 -0
  126. patchi/core/ai/agent_audit.py +153 -0
  127. patchi/core/ai/agent_profiler.py +277 -0
  128. patchi/core/ai/client.py +499 -0
  129. patchi/core/ai/cost_tracker.py +107 -0
  130. patchi/core/ai/model_router.py +318 -0
  131. patchi/core/ai/orchestrator.py +625 -0
  132. patchi/core/ai/prompts.py +681 -0
  133. patchi/core/ai/smart.py +302 -0
  134. patchi/core/ai/tool_executor.py +24 -0
  135. patchi/core/ai/tools/__init__.py +10 -0
  136. patchi/core/ai/tools/executor.py +621 -0
  137. patchi/core/ai/tools/realize.py +1160 -0
  138. patchi/core/ai/tools/registry.py +1577 -0
  139. patchi/core/assurance/__init__.py +33 -0
  140. patchi/core/assurance/builder.py +211 -0
  141. patchi/core/assurance/graph.py +342 -0
  142. patchi/core/assurance/invariants.py +168 -0
  143. patchi/core/atomic.py +61 -0
  144. patchi/core/attackers/__init__.py +17 -0
  145. patchi/core/attackers/api_abuse.py +89 -0
  146. patchi/core/attackers/auth_bypass.py +73 -0
  147. patchi/core/attackers/base.py +91 -0
  148. patchi/core/attackers/business_logic.py +88 -0
  149. patchi/core/attackers/planner.py +108 -0
  150. patchi/core/attackers/priv_escalation.py +88 -0
  151. patchi/core/attackers/recon.py +87 -0
  152. patchi/core/brain/__init__.py +0 -0
  153. patchi/core/brain/ast_utils/__init__.py +81 -0
  154. patchi/core/brain/ast_utils/assignments.py +219 -0
  155. patchi/core/brain/ast_utils/calls.py +139 -0
  156. patchi/core/brain/ast_utils/config.py +132 -0
  157. patchi/core/brain/ast_utils/control_flow.py +74 -0
  158. patchi/core/brain/ast_utils/dead_symbols.py +205 -0
  159. patchi/core/brain/ast_utils/decorators.py +108 -0
  160. patchi/core/brain/ast_utils/helpers.py +144 -0
  161. patchi/core/brain/ast_utils/imports.py +169 -0
  162. patchi/core/brain/ast_utils/scan.py +143 -0
  163. patchi/core/brain/ast_utils/taint.py +310 -0
  164. patchi/core/brain/audit.py +379 -0
  165. patchi/core/brain/baseline.py +195 -0
  166. patchi/core/brain/blast_radius.py +312 -0
  167. patchi/core/brain/body_tags.py +144 -0
  168. patchi/core/brain/brain.py +1161 -0
  169. patchi/core/brain/brain_context.py +393 -0
  170. patchi/core/brain/brain_watcher.py +340 -0
  171. patchi/core/brain/charter.py +473 -0
  172. patchi/core/brain/classifier.py +214 -0
  173. patchi/core/brain/cockpit.py +350 -0
  174. patchi/core/brain/code_query.py +710 -0
  175. patchi/core/brain/contract.py +889 -0
  176. patchi/core/brain/contract_diff.py +155 -0
  177. patchi/core/brain/council.py +800 -0
  178. patchi/core/brain/cross_repo.py +104 -0
  179. patchi/core/brain/dead_code_tools.py +157 -0
  180. patchi/core/brain/doc_validator.py +197 -0
  181. patchi/core/brain/domain_activator.py +2183 -0
  182. patchi/core/brain/enriched_context.py +220 -0
  183. patchi/core/brain/file_corpus.py +220 -0
  184. patchi/core/brain/framework.py +953 -0
  185. patchi/core/brain/freshness.py +273 -0
  186. patchi/core/brain/git_aware.py +206 -0
  187. patchi/core/brain/heatmap.py +104 -0
  188. patchi/core/brain/ignore_parser.py +153 -0
  189. patchi/core/brain/import_graph.py +486 -0
  190. patchi/core/brain/languages.py +397 -0
  191. patchi/core/brain/layered_brain.py +419 -0
  192. patchi/core/brain/learning.py +229 -0
  193. patchi/core/brain/orphaned_endpoints.py +313 -0
  194. patchi/core/brain/personas/__init__.py +648 -0
  195. patchi/core/brain/personas/bad_user.py +165 -0
  196. patchi/core/brain/personas/base.py +349 -0
  197. patchi/core/brain/proactive.py +807 -0
  198. patchi/core/brain/project_context.py +121 -0
  199. patchi/core/brain/project_reader.py +521 -0
  200. patchi/core/brain/reasoning.py +269 -0
  201. patchi/core/brain/route_detector/__init__.py +15 -0
  202. patchi/core/brain/route_detector/base.py +31 -0
  203. patchi/core/brain/route_detector/csharp.py +209 -0
  204. patchi/core/brain/route_detector/file_based.py +81 -0
  205. patchi/core/brain/route_detector/go.py +152 -0
  206. patchi/core/brain/route_detector/java.py +195 -0
  207. patchi/core/brain/route_detector/javascript.py +197 -0
  208. patchi/core/brain/route_detector/php.py +158 -0
  209. patchi/core/brain/route_detector/python.py +193 -0
  210. patchi/core/brain/route_detector/registry.py +25 -0
  211. patchi/core/brain/route_detector/ruby.py +134 -0
  212. patchi/core/brain/route_detector/rust.py +216 -0
  213. patchi/core/brain/route_detector/swift.py +118 -0
  214. patchi/core/brain/route_mapper.py +265 -0
  215. patchi/core/brain/scanner.py +2136 -0
  216. patchi/core/brain/secrets.py +280 -0
  217. patchi/core/brain/symbol_graph.py +1955 -0
  218. patchi/core/brain/team.py +28 -0
  219. patchi/core/brain/trace_log.py +132 -0
  220. patchi/core/brain/type_checker/__init__.py +65 -0
  221. patchi/core/brain/type_checker/base.py +60 -0
  222. patchi/core/brain/type_checker/csharp.py +59 -0
  223. patchi/core/brain/type_checker/dart.py +59 -0
  224. patchi/core/brain/type_checker/go.py +81 -0
  225. patchi/core/brain/type_checker/java.py +75 -0
  226. patchi/core/brain/type_checker/kotlin.py +75 -0
  227. patchi/core/brain/type_checker/php.py +88 -0
  228. patchi/core/brain/type_checker/python.py +87 -0
  229. patchi/core/brain/type_checker/rust.py +81 -0
  230. patchi/core/brain/type_checker/swift.py +59 -0
  231. patchi/core/brain/type_checker/typescript.py +298 -0
  232. patchi/core/brain/understander.py +130 -0
  233. patchi/core/brain/verify.py +379 -0
  234. patchi/core/campaigns/__init__.py +14 -0
  235. patchi/core/campaigns/base.py +62 -0
  236. patchi/core/campaigns/data_flow_abuse.py +153 -0
  237. patchi/core/campaigns/orchestrator.py +140 -0
  238. patchi/core/campaigns/state_transitions.py +178 -0
  239. patchi/core/ci_bundle.py +104 -0
  240. patchi/core/config.py +311 -0
  241. patchi/core/constants.py +245 -0
  242. patchi/core/debug/__init__.py +25 -0
  243. patchi/core/debug/adapters/__init__.py +11 -0
  244. patchi/core/debug/adapters/codelldb.py +379 -0
  245. patchi/core/debug/adapters/node.py +222 -0
  246. patchi/core/debug/adapters/powershell.py +210 -0
  247. patchi/core/debug/adapters/python.py +244 -0
  248. patchi/core/debug/capture.py +210 -0
  249. patchi/core/debug/dap_client.py +268 -0
  250. patchi/core/detector/__init__.py +0 -0
  251. patchi/core/detector/audit.py +194 -0
  252. patchi/core/detector/bus.py +226 -0
  253. patchi/core/detector/dispatcher.py +275 -0
  254. patchi/core/detector/event.py +254 -0
  255. patchi/core/detector/sigma_engine.py +378 -0
  256. patchi/core/detector/triage.py +289 -0
  257. patchi/core/export/sarif.py +113 -0
  258. patchi/core/fix/__init__.py +17 -0
  259. patchi/core/fix/applier.py +574 -0
  260. patchi/core/fix/base.py +510 -0
  261. patchi/core/fix/code_fixer.py +169 -0
  262. patchi/core/fix/dead_code_remover.py +131 -0
  263. patchi/core/fix/fix_agents.py +775 -0
  264. patchi/core/fix/patch.py +444 -0
  265. patchi/core/fix/risk_gate.py +383 -0
  266. patchi/core/fix/security_fixer.py +93 -0
  267. patchi/core/fix/verify_loop.py +204 -0
  268. patchi/core/fuzz/__init__.py +8 -0
  269. patchi/core/fuzz/corpus.py +137 -0
  270. patchi/core/fuzz/input_fuzzer.py +256 -0
  271. patchi/core/fuzz/sequence_fuzzer.py +162 -0
  272. patchi/core/fuzz/state_fuzzer.py +236 -0
  273. patchi/core/health.py +407 -0
  274. patchi/core/hosted/__init__.py +1 -0
  275. patchi/core/hosted/anomaly.py +298 -0
  276. patchi/core/hosted/audit_log.py +102 -0
  277. patchi/core/hosted/compliance_report.py +148 -0
  278. patchi/core/hosted/ip_reputation.py +169 -0
  279. patchi/core/hosted/log_parsers.py +251 -0
  280. patchi/core/hosted/tokens.py +127 -0
  281. patchi/core/hosted/watchlist.py +164 -0
  282. patchi/core/hosted/webhooks.py +156 -0
  283. patchi/core/memory.py +437 -0
  284. patchi/core/notifications/__init__.py +18 -0
  285. patchi/core/notifications/channels.py +192 -0
  286. patchi/core/notifications/digest.py +141 -0
  287. patchi/core/notifications/escalation.py +158 -0
  288. patchi/core/notifications/notifier.py +182 -0
  289. patchi/core/notifications/quiet_hours.py +69 -0
  290. patchi/core/plugins/__init__.py +48 -0
  291. patchi/core/plugins/analyzer.py +326 -0
  292. patchi/core/plugins/analyzers/__init__.py +6 -0
  293. patchi/core/plugins/analyzers/dead_code_analyzer.py +120 -0
  294. patchi/core/plugins/analyzers/secret_scanner.py +158 -0
  295. patchi/core/plugins/analyzers/todo_scanner.py +115 -0
  296. patchi/core/plugins/registry.py +335 -0
  297. patchi/core/queue.py +375 -0
  298. patchi/core/reliability/__init__.py +13 -0
  299. patchi/core/reliability/chaos.py +163 -0
  300. patchi/core/reliability/fault_injector.py +172 -0
  301. patchi/core/reliability/idempotency.py +128 -0
  302. patchi/core/reliability/recovery.py +147 -0
  303. patchi/core/runtime/__init__.py +5 -0
  304. patchi/core/runtime/tracer.py +230 -0
  305. patchi/core/scan_bus.py +156 -0
  306. patchi/core/security/__init__.py +1 -0
  307. patchi/core/security/ai_validator.py +462 -0
  308. patchi/core/security/app_mapper.py +216 -0
  309. patchi/core/security/app_profile.py +464 -0
  310. patchi/core/security/attack_feedback.py +141 -0
  311. patchi/core/security/attack_scenarios/__init__.py +1 -0
  312. patchi/core/security/attack_tree.py +176 -0
  313. patchi/core/security/auth_audit_agent.py +344 -0
  314. patchi/core/security/authz_agent.py +602 -0
  315. patchi/core/security/auto_fix_proactive.py +620 -0
  316. patchi/core/security/auto_fixer.py +660 -0
  317. patchi/core/security/auto_ticket.py +53 -0
  318. patchi/core/security/bandit_agent.py +152 -0
  319. patchi/core/security/blast_radius.py +226 -0
  320. patchi/core/security/browser_tester.py +333 -0
  321. patchi/core/security/business_logic_agent.py +263 -0
  322. patchi/core/security/catch_block_auditor.py +395 -0
  323. patchi/core/security/cdn_cache_agent.py +357 -0
  324. patchi/core/security/chain_analyzer.py +321 -0
  325. patchi/core/security/chain_to_assurance.py +168 -0
  326. patchi/core/security/charter.py +510 -0
  327. patchi/core/security/cloud_waf_detector.py +295 -0
  328. patchi/core/security/codeql_agent.py +233 -0
  329. patchi/core/security/compliance_agent.py +348 -0
  330. patchi/core/security/confidence_gate.py +423 -0
  331. patchi/core/security/container_scanner.py +282 -0
  332. patchi/core/security/crypto_agent.py +378 -0
  333. patchi/core/security/cve_monitor.py +262 -0
  334. patchi/core/security/dast_agent.py +865 -0
  335. patchi/core/security/defectdojo.py +238 -0
  336. patchi/core/security/defenders/__init__.py +75 -0
  337. patchi/core/security/defenders/auth_middleware.py +115 -0
  338. patchi/core/security/defenders/base.py +97 -0
  339. patchi/core/security/defenders/block_ip.py +71 -0
  340. patchi/core/security/defenders/block_ws_origin.py +36 -0
  341. patchi/core/security/defenders/crypto_fix.py +118 -0
  342. patchi/core/security/defenders/enforce_rate_limit.py +108 -0
  343. patchi/core/security/defenders/fix_code.py +93 -0
  344. patchi/core/security/defenders/invalidate_session.py +40 -0
  345. patchi/core/security/defenders/patch_config.py +70 -0
  346. patchi/core/security/defenders/rotate_secret.py +54 -0
  347. patchi/core/security/defenders/suspend_account.py +41 -0
  348. patchi/core/security/defenders/update_dependency.py +160 -0
  349. patchi/core/security/defense_layer.py +217 -0
  350. patchi/core/security/dependency_vulnerability_agent.py +616 -0
  351. patchi/core/security/detection_pipeline.py +289 -0
  352. patchi/core/security/dns_security_agent.py +497 -0
  353. patchi/core/security/domain_activator_v2.py +913 -0
  354. patchi/core/security/domain_loader.py +1004 -0
  355. patchi/core/security/domains/__init__.py +0 -0
  356. patchi/core/security/email_authentication_agent.py +417 -0
  357. patchi/core/security/env_var_validator.py +304 -0
  358. patchi/core/security/evidence.py +100 -0
  359. patchi/core/security/falco_runtime_agent.py +387 -0
  360. patchi/core/security/fix-playbooks/__init__.py +0 -0
  361. patchi/core/security/gated_finding.py +85 -0
  362. patchi/core/security/git_diff_activator.py +367 -0
  363. patchi/core/security/governance.py +208 -0
  364. patchi/core/security/gradual_gate.py +34 -0
  365. patchi/core/security/history.py +315 -0
  366. patchi/core/security/iac_scanner.py +250 -0
  367. patchi/core/security/ignore_expiry.py +111 -0
  368. patchi/core/security/ignore_learner.py +416 -0
  369. patchi/core/security/injection_agent.py +319 -0
  370. patchi/core/security/insecure_randomness_agent.py +288 -0
  371. patchi/core/security/intent_analyzer.py +326 -0
  372. patchi/core/security/jwt_agent.py +453 -0
  373. patchi/core/security/kubernetes_agent.py +638 -0
  374. patchi/core/security/layer2_orchestrator.py +341 -0
  375. patchi/core/security/llm_security_agent.py +252 -0
  376. patchi/core/security/misconfig_agent.py +600 -0
  377. patchi/core/security/mobile_security_agent.py +474 -0
  378. patchi/core/security/network_agent.py +376 -0
  379. patchi/core/security/noise_filter.py +274 -0
  380. patchi/core/security/orchestrator.py +313 -0
  381. patchi/core/security/pattern_context.py +125 -0
  382. patchi/core/security/pattern_loader.py +101 -0
  383. patchi/core/security/pentest/__init__.py +4 -0
  384. patchi/core/security/pentest/base.py +58 -0
  385. patchi/core/security/pentest/dalfox_adapter.py +40 -0
  386. patchi/core/security/pentest/ffuf_adapter.py +48 -0
  387. patchi/core/security/pentest/nuclei_adapter.py +50 -0
  388. patchi/core/security/pentest/registry.py +80 -0
  389. patchi/core/security/pentest/shannon_adapter.py +107 -0
  390. patchi/core/security/pentest/sqlmap_adapter.py +56 -0
  391. patchi/core/security/pentest/zap_adapter.py +52 -0
  392. patchi/core/security/plan_auditor.py +276 -0
  393. patchi/core/security/policy_engine.py +272 -0
  394. patchi/core/security/prechecks.py +172 -0
  395. patchi/core/security/precommit_hook.py +247 -0
  396. patchi/core/security/privacy_agent.py +361 -0
  397. patchi/core/security/push_notification_agent.py +417 -0
  398. patchi/core/security/pysa_agent.py +143 -0
  399. patchi/core/security/reasoning.py +442 -0
  400. patchi/core/security/red_team_agent.py +184 -0
  401. patchi/core/security/red_team_engine.py +1142 -0
  402. patchi/core/security/remediation.py +360 -0
  403. patchi/core/security/request_interceptor.py +294 -0
  404. patchi/core/security/runtime_validator.py +245 -0
  405. patchi/core/security/saml_sso_agent.py +401 -0
  406. patchi/core/security/sast_agent.py +213 -0
  407. patchi/core/security/sast_gate.py +95 -0
  408. patchi/core/security/scheduler.py +287 -0
  409. patchi/core/security/secrets_runtime_agent.py +476 -0
  410. patchi/core/security/security_agents.py +175 -0
  411. patchi/core/security/security_config.py +551 -0
  412. patchi/core/security/security_probe.py +762 -0
  413. patchi/core/security/security_taint.py +1005 -0
  414. patchi/core/security/sensitive_data_agent.py +271 -0
  415. patchi/core/security/service_mesh_agent.py +412 -0
  416. patchi/core/security/session_management_agent.py +245 -0
  417. patchi/core/security/ssrf_agent.py +422 -0
  418. patchi/core/security/supply_chain.py +449 -0
  419. patchi/core/security/threat_model_generator.py +378 -0
  420. patchi/core/security/threat_model_updater.py +196 -0
  421. patchi/core/security/tool_adapters.py +135 -0
  422. patchi/core/security/tool_verify.py +173 -0
  423. patchi/core/security/websocket_security_agent.py +188 -0
  424. patchi/core/snapshot.py +242 -0
  425. patchi/core/tenant.py +386 -0
  426. patchi/core/testing/__init__.py +17 -0
  427. patchi/core/testing/_browser.py +147 -0
  428. patchi/core/testing/ads_agent.py +141 -0
  429. patchi/core/testing/api_contract_agent.py +450 -0
  430. patchi/core/testing/app_discovery_agent.py +641 -0
  431. patchi/core/testing/app_launcher.py +184 -0
  432. patchi/core/testing/browser_test_agent.py +516 -0
  433. patchi/core/testing/e2e_flow_agent.py +354 -0
  434. patchi/core/testing/flake_detector_agent.py +292 -0
  435. patchi/core/testing/gate.py +31 -0
  436. patchi/core/testing/live_test_runner.py +304 -0
  437. patchi/core/testing/live_v2/__init__.py +1 -0
  438. patchi/core/testing/live_v2/browser_pool.py +349 -0
  439. patchi/core/testing/live_v2/browser_test_runner.py +313 -0
  440. patchi/core/testing/live_v2/runner.py +626 -0
  441. patchi/core/testing/live_v2/screenshot_manager.py +474 -0
  442. patchi/core/testing/live_v2/stress_orchestrator.py +523 -0
  443. patchi/core/testing/live_v2/video_recorder.py +303 -0
  444. patchi/core/testing/regression_agent.py +302 -0
  445. patchi/core/testing/security_test_agent.py +253 -0
  446. patchi/core/testing/stress_test_agent.py +203 -0
  447. patchi/core/testing/test_agents.py +50 -0
  448. patchi/core/testing/test_config.py +194 -0
  449. patchi/core/testing/ui_accessibility_agent.py +324 -0
  450. patchi/core/testing/ui_button_agent.py +294 -0
  451. patchi/core/testing/ui_layout_agent.py +330 -0
  452. patchi/core/testing/unit_test_agent.py +1149 -0
  453. patchi/core/testing/visual_regression_agent.py +260 -0
  454. patchi/web/__init__.py +1 -0
  455. patchi/web/api/__init__.py +1 -0
  456. patchi/web/api/brain_map.py +114 -0
  457. patchi/web/api/charts.py +47 -0
  458. patchi/web/api/chat.py +224 -0
  459. patchi/web/api/cicd.py +576 -0
  460. patchi/web/api/dast_evidence.py +49 -0
  461. patchi/web/api/dev_check.py +320 -0
  462. patchi/web/api/fix.py +134 -0
  463. patchi/web/api/guard.py +65 -0
  464. patchi/web/api/hosted.py +128 -0
  465. patchi/web/api/hosted_v2.py +234 -0
  466. patchi/web/api/live_testing.py +699 -0
  467. patchi/web/api/scan.py +582 -0
  468. patchi/web/api/smart.py +111 -0
  469. patchi/web/api/tenant.py +117 -0
  470. patchi/web/api/tools.py +85 -0
  471. patchi/web/api_legacy.py +2401 -0
  472. patchi/web/app.py +310 -0
  473. patchi/web/events.py +483 -0
  474. patchi/web/routes/__init__.py +1 -0
  475. patchi/web/routes/assurance.py +541 -0
  476. patchi/web/routes/brain.py +36 -0
  477. patchi/web/routes/charter.py +227 -0
  478. patchi/web/routes/chat.py +23 -0
  479. patchi/web/routes/dashboard.py +558 -0
  480. patchi/web/routes/dashboard_v2.py +402 -0
  481. patchi/web/routes/findings.py +330 -0
  482. patchi/web/routes/guard.py +35 -0
  483. patchi/web/routes/history.py +126 -0
  484. patchi/web/routes/landing.py +52 -0
  485. patchi/web/routes/live_testing.py +24 -0
  486. patchi/web/routes/review.py +57 -0
  487. patchi/web/routes/self_improvement.py +110 -0
  488. patchi/web/routes/settings.py +49 -0
  489. patchi/web/routes/tokens.py +29 -0
  490. patchi/web/spawn.py +139 -0
  491. patchi/web/ws.py +141 -0
  492. patchi-0.7.5.dist-info/METADATA +315 -0
  493. patchi-0.7.5.dist-info/RECORD +496 -0
  494. patchi-0.7.5.dist-info/WHEEL +5 -0
  495. patchi-0.7.5.dist-info/licenses/LICENSE +60 -0
  496. patchi-0.7.5.dist-info/top_level.txt +1 -0
@@ -0,0 +1,286 @@
1
+ """RefactoringAgent — resource leaks, cleanup hygiene, modernization.
2
+
3
+ Covers §7.1.3-4 and §7.3.1-3:
4
+ - Dependency sorting (isort, goimports, rustfmt)
5
+ - Modernization patterns (var→const/let, .then()→async/await, require→import)
6
+ - Resource leak detection (setInterval without clearInterval)
7
+ - React effect cleanup (useEffect without cleanup)
8
+ - File handle tracking (streams without close)
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import ast
14
+ import logging
15
+ from pathlib import Path
16
+
17
+ from ..brain.code_query import (
18
+ js_call_names,
19
+ js_calls,
20
+ js_useeffect_without_cleanup,
21
+ lang_for_file,
22
+ parse_js,
23
+ )
24
+ from ..brain.languages import DEFAULT_IGNORE_DIRS
25
+ from .base import (
26
+ AgentGroup,
27
+ AgentInput,
28
+ AgentResult,
29
+ AgentStatus,
30
+ BaseAgent,
31
+ Severity,
32
+ make_finding,
33
+ register,
34
+ safe_rglob,
35
+ )
36
+
37
+ _log = logging.getLogger("patchi.agents.refactoring_agent")
38
+
39
+
40
+ def _detect_interval_without_cleanup(content: str, lang: str) -> list[dict]:
41
+ findings: list[dict] = []
42
+ tree = parse_js(content, lang)
43
+ if tree is None:
44
+ return findings
45
+ names = js_call_names(tree, lang)
46
+ if "setInterval" in names and "clearInterval" not in names:
47
+ for call in js_calls(tree, lang):
48
+ if call.name == "setInterval":
49
+ findings.append({"line": call.line, "type": "setInterval"})
50
+ break
51
+ return findings
52
+
53
+
54
+ def _detect_effect_without_cleanup(content: str, lang: str) -> list[dict]:
55
+ return [
56
+ {"line": line, "type": "useEffect_no_cleanup"}
57
+ for line in js_useeffect_without_cleanup(parse_js(content, lang), lang)
58
+ ]
59
+
60
+
61
+ def _detect_py_file_handle_leaks(content: str) -> list[dict]:
62
+ """Python open() outside a with-statement, via stdlib ast."""
63
+ findings: list[dict] = []
64
+ try:
65
+ tree = ast.parse(content)
66
+ except SyntaxError:
67
+ return findings
68
+
69
+ def _is_open(node) -> bool:
70
+ return isinstance(node, ast.Call) and getattr(node.func, "id", "") == "open"
71
+
72
+ guarded: set[int] = set()
73
+ for node in ast.walk(tree):
74
+ if isinstance(node, ast.With):
75
+ for item in node.items:
76
+ for n in ast.walk(item.context_expr):
77
+ if _is_open(n):
78
+ guarded.add(n.lineno)
79
+ for node in ast.walk(tree):
80
+ if _is_open(node) and node.lineno not in guarded:
81
+ findings.append({"line": node.lineno, "resource": "open()", "type": "file_handle"})
82
+ return findings
83
+
84
+
85
+ def _detect_file_handle_leaks(content: str, lang: str) -> list[dict]:
86
+ findings: list[dict] = []
87
+ tree = parse_js(content, lang)
88
+ if tree is None:
89
+ return findings
90
+ names = js_call_names(tree, lang)
91
+ opened = [c for c in js_calls(tree, lang) if c.name in ("createReadStream", "createWriteStream") or c.full == "fs.open"]
92
+ if opened and not names & {"close", "destroy", "end"}:
93
+ first = opened[0]
94
+ findings.append({"line": first.line, "resource": first.full or first.name, "type": "file_handle"})
95
+ return findings
96
+
97
+
98
+ def _detect_file_handle_leaks_legacy(content: str) -> list[dict]:
99
+ """Fallback for languages without an installed tree-sitter grammar.
100
+
101
+ Regex is the only available tool here (no parser installed); kept
102
+ deliberately narrow and documented.
103
+ """
104
+ import re
105
+
106
+ findings: list[dict] = []
107
+ lines = content.splitlines()
108
+ streams: dict[str, int] = {}
109
+ for i, line in enumerate(lines):
110
+ for pat in [
111
+ r"(?:createReadStream|createWriteStream)\s*\(\s*([^)]+)\)",
112
+ r"open\s*\(\s*['\"]([^'\"]+)",
113
+ ]:
114
+ m = re.search(pat, line)
115
+ if m:
116
+ ident = m.group(1)[:20]
117
+ streams[ident] = i + 1
118
+ if re.search(r"\.(close|destroy|end)\s*\(", line):
119
+ for k in list(streams.keys()):
120
+ streams.pop(k, None)
121
+ for ident, line in streams.items():
122
+ findings.append({"line": line, "resource": ident, "type": "file_handle"})
123
+ return findings
124
+
125
+
126
+ def _detect_modernization_candidates(content: str, ext: str, lang: str) -> list[dict]:
127
+ findings: list[dict] = []
128
+ tree = parse_js(content, lang)
129
+ if tree is None:
130
+ return findings
131
+ from ..brain.code_query import js_var_kinds
132
+
133
+ lines = content.splitlines()
134
+ for kind, line in js_var_kinds(tree, lang):
135
+ if kind == "var":
136
+ text = lines[line - 1].strip()[:60] if 0 < line <= len(lines) else ""
137
+ findings.append({"line": line, "type": "var_to_const_let", "text": text})
138
+ for call in js_calls(tree, lang):
139
+ if call.name != "then":
140
+ continue
141
+ text = lines[call.line - 1] if 0 < call.line <= len(lines) else ""
142
+ if "async" in text or "await" in text:
143
+ continue
144
+ findings.append({"line": call.line, "type": "then_to_async_await", "text": text.strip()[:60]})
145
+ if "require" in js_call_names(tree, lang) and "import " not in content:
146
+ for call in js_calls(tree, lang):
147
+ if call.name == "require":
148
+ text = lines[call.line - 1] if 0 < call.line <= len(lines) else ""
149
+ findings.append({"line": call.line, "type": "require_to_import", "text": text.strip()[:60]})
150
+ return findings
151
+
152
+
153
+ @register
154
+ class RefactoringAgent(BaseAgent):
155
+ """Detects resource leaks, missing cleanup, and modernization opportunities."""
156
+
157
+ group = AgentGroup.SCANNER
158
+ name = "RefactoringAgent"
159
+ description = "Resource leaks, React effect cleanup, file handles, modernization patterns"
160
+
161
+ def _run(self, inp: AgentInput, result: AgentResult) -> None:
162
+ interval_leaks: list[dict] = []
163
+ effect_issues: list[dict] = []
164
+ file_handle_leaks: list[dict] = []
165
+ modernization: list[dict] = []
166
+ files_scanned = 0
167
+
168
+ for file_path in safe_rglob(inp.root, "*"):
169
+ rel = file_path.relative_to(inp.root).as_posix()
170
+ if any(seg in DEFAULT_IGNORE_DIRS for seg in Path(rel).parts):
171
+ continue
172
+ ext = file_path.suffix.lower()
173
+ if ext not in (
174
+ ".js",
175
+ ".jsx",
176
+ ".ts",
177
+ ".tsx",
178
+ ".py",
179
+ ".rs",
180
+ ".go",
181
+ ".java",
182
+ ".c",
183
+ ".cpp",
184
+ ".swift",
185
+ ".rb",
186
+ ".svelte",
187
+ ):
188
+ continue
189
+ files_scanned += 1
190
+ try:
191
+ content = file_path.read_text(encoding="utf-8")
192
+ except Exception as e:
193
+ _log.warning("RefactoringAgent._run failed: %s", e)
194
+ continue
195
+
196
+ if ext in (".js", ".jsx", ".ts", ".tsx", ".svelte"):
197
+ lang = lang_for_file(rel)
198
+ interval_leaks.extend(
199
+ {"file": rel, **f} for f in _detect_interval_without_cleanup(content, lang)
200
+ )
201
+ effect_issues.extend(
202
+ {"file": rel, **f} for f in _detect_effect_without_cleanup(content, lang)
203
+ )
204
+ modernization.extend(
205
+ {"file": rel, **f} for f in _detect_modernization_candidates(content, ext, lang)
206
+ )
207
+
208
+ if ext in (".js", ".jsx", ".ts", ".tsx"):
209
+ file_handle_leaks.extend(
210
+ {"file": rel, **f}
211
+ for f in _detect_file_handle_leaks(content, lang_for_file(rel))
212
+ )
213
+ elif ext == ".py":
214
+ file_handle_leaks.extend(
215
+ {"file": rel, **f} for f in _detect_py_file_handle_leaks(content)
216
+ )
217
+ elif ext in (".rs", ".go", ".java", ".c", ".cpp"):
218
+ file_handle_leaks.extend(
219
+ {"file": rel, **f} for f in _detect_file_handle_leaks_legacy(content)
220
+ )
221
+
222
+ result.data["interval_leaks"] = interval_leaks
223
+ result.data["effect_issues"] = effect_issues
224
+ result.data["file_handle_leaks"] = file_handle_leaks
225
+ result.data["modernization"] = modernization
226
+
227
+ for f in interval_leaks:
228
+ result.findings.append(
229
+ make_finding(
230
+ self.name,
231
+ "resource_leak",
232
+ Severity.MEDIUM,
233
+ f["file"],
234
+ f"Resource leak: {f['type']} without matching clearInterval",
235
+ line=f["line"],
236
+ suggestion="Assign setInterval to a variable and call clearInterval() on unmount",
237
+ )
238
+ )
239
+ for f in effect_issues:
240
+ result.findings.append(
241
+ make_finding(
242
+ self.name,
243
+ "effect_cleanup",
244
+ Severity.MEDIUM,
245
+ f["file"],
246
+ "useEffect without cleanup function",
247
+ line=f["line"],
248
+ detail="Subscriptions/timers in useEffect must return a cleanup function",
249
+ suggestion="Add a return cleanup function to prevent memory leaks",
250
+ )
251
+ )
252
+ for f in file_handle_leaks:
253
+ result.findings.append(
254
+ make_finding(
255
+ self.name,
256
+ "file_handle_leak",
257
+ Severity.MEDIUM,
258
+ f["file"],
259
+ f"Potential file handle leak: {f.get('resource', '?')}",
260
+ line=f["line"],
261
+ detail="Stream/file opened without matching close/destroy",
262
+ suggestion="Ensure .close() or .destroy() is called in all code paths",
263
+ )
264
+ )
265
+ for f in modernization:
266
+ type_labels = {
267
+ "var_to_const_let": "Replace var with const/let",
268
+ "then_to_async_await": "Consider using async/await instead of .then()",
269
+ "require_to_import": "Replace require() with import statement",
270
+ }
271
+ result.findings.append(
272
+ make_finding(
273
+ self.name,
274
+ f["type"],
275
+ Severity.LOW,
276
+ f["file"],
277
+ type_labels.get(f["type"], f["type"]),
278
+ line=f["line"],
279
+ detail=f["text"],
280
+ suggestion="Apply modernization codemod",
281
+ )
282
+ )
283
+
284
+ result.files_scanned = files_scanned
285
+ if result.status == AgentStatus.RUNNING:
286
+ result.status = AgentStatus.DONE
@@ -0,0 +1,91 @@
1
+ """
2
+ ResourceLeakAgent §7.3.1-3 — setInterval/setTimeout/EventEmitter without cleanup, useEffect without cleanup, file handle not closed.
3
+
4
+ Tree-sitter pattern: setInterval without clearInterval in same scope; useEffect return missing; createReadStream without close/destroy.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+
11
+ from patchi.core.agents.base import (
12
+ AgentGroup,
13
+ AgentInput,
14
+ AgentResult,
15
+ AgentStatus,
16
+ BaseAgent,
17
+ Severity,
18
+ make_finding,
19
+ register,
20
+ safe_rglob,
21
+ )
22
+ from patchi.core.brain.code_query import (
23
+ js_calls,
24
+ js_useeffect_without_cleanup,
25
+ lang_for_file,
26
+ parse_js,
27
+ )
28
+
29
+ _log = logging.getLogger("patchi.agents.resource_leak")
30
+
31
+ @register
32
+ class ResourceLeakAgent(BaseAgent):
33
+ group = AgentGroup.SCANNER
34
+ name = "ResourceLeakAgent"
35
+ description = "Resource leak §7.3 setInterval/EventEmitter/useEffect/stream without cleanup"
36
+ timeout = 60
37
+
38
+ def _run(self, inp: AgentInput, result: AgentResult) -> None:
39
+ findings=[]
40
+ for pat in ("*.js","*.jsx","*.ts","*.tsx"):
41
+ for fp in safe_rglob(inp.root, pat):
42
+ rel=fp.relative_to(inp.root).as_posix()
43
+ if "node_modules" in rel or "tests" in rel:
44
+ continue
45
+ try:
46
+ txt=fp.read_text(encoding="utf-8", errors="replace")
47
+ except OSError:
48
+ continue
49
+ tree=parse_js(txt, lang_for_file(rel))
50
+ if tree is None:
51
+ continue
52
+ calls=js_calls(tree, lang_for_file(rel))
53
+ names={c.name for c in calls}
54
+ by_name: dict[str, list] = {}
55
+ for c in calls:
56
+ by_name.setdefault(c.name, []).append(c)
57
+ first_interval = by_name["setInterval"][0].line if "setInterval" in by_name else 0
58
+
59
+ has_interval = "setInterval" in names
60
+ has_clear = "clearInterval" in names
61
+ has_emitter = any(
62
+ c.name == "on" and c.arg_kinds[:1] == ["string"] for c in calls
63
+ )
64
+ has_off = bool(names & {"removeListener", "off", "removeEventListener"})
65
+ no_cleanup_lines = js_useeffect_without_cleanup(tree, lang_for_file(rel))
66
+ stream_call = next(
67
+ (c for c in calls if c.name in ("createReadStream", "createWriteStream") or c.full == "fs.open"),
68
+ None,
69
+ )
70
+ has_stream = stream_call is not None
71
+ has_close = bool(names & {"close", "destroy", "end"})
72
+
73
+ # Interval leak
74
+ if has_interval and not has_clear:
75
+ findings.append(make_finding(severity=Severity.MEDIUM, file=rel, line_start=first_interval, title="setInterval without clearInterval", description="Leaks interval; store handle and clearInterval on unmount/cleanup", finding_type="resource_leak_interval"))
76
+ # Emitter leak
77
+ if has_emitter and not has_off:
78
+ line = next((c.line for c in calls if c.name == "on" and c.arg_kinds[:1] == ["string"]), 0)
79
+ findings.append(make_finding(severity=Severity.LOW, file=rel, line_start=line, title="EventEmitter .on without off/cleanup", description="Add removeListener/off in cleanup", finding_type="resource_leak_emitter"))
80
+ # useEffect without cleanup
81
+ if no_cleanup_lines and has_interval:
82
+ findings.append(make_finding(severity=Severity.LOW, file=rel, line_start=no_cleanup_lines[0], title="useEffect with interval but no cleanup return", description="Return () => clearInterval in useEffect", finding_type="resource_leak_effect"))
83
+ # Stream not closed
84
+ if has_stream and not has_close and stream_call is not None:
85
+ findings.append(make_finding(severity=Severity.LOW, file=rel, line_start=stream_call.line, title="Stream without close/destroy", description="Ensure fs stream closed/destroyed", finding_type="resource_leak_stream"))
86
+ if len(findings) >= 40:
87
+ break
88
+ if len(findings) >= 40:
89
+ break
90
+ result.status=AgentStatus.SUCCEEDED
91
+ result.findings=findings[:40]