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,395 @@
1
+ """
2
+ CatchBlockAuditor — Detects empty or bare catch/except blocks.
3
+
4
+ Finds error handlers that swallow exceptions:
5
+ - Empty catch/except blocks: `catch (e) {}` or `except: pass`
6
+ - Bare logging without re-raise: `catch (e) { console.log(e); }`
7
+ - Swallowed exceptions with no action: `catch {}`
8
+ - Silent failure: bare `except:` without specifying exception type
9
+
10
+ Covers all languages with tree-sitter via AST walkers where a try/catch
11
+ construct exists; Go (ignored `err`) and Rust (`unwrap`) are handled with
12
+ targeted checks since they have no exception-handling blocks.
13
+
14
+ Uses AST structure (accurate block boundaries) + lightweight text analysis
15
+ of the handler body to decide whether it does something useful.
16
+ Does NOT call AI.
17
+ Does NOT write to disk.
18
+ Does NOT touch the queue.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import logging
24
+ import re
25
+ from pathlib import Path
26
+
27
+ from ..agents.base import (
28
+ AgentGroup,
29
+ AgentInput,
30
+ AgentResult,
31
+ AgentStatus,
32
+ BaseAgent,
33
+ Finding,
34
+ Severity,
35
+ make_finding,
36
+ register,
37
+ safe_rglob,
38
+ )
39
+ from ..brain.ast_utils import (
40
+ child_by_field,
41
+ find_assignments,
42
+ find_calls,
43
+ named_children,
44
+ node_text,
45
+ parse_source,
46
+ )
47
+ from ..brain.languages import EXTENSION_MAP, Lang
48
+ from ..brain.trace_log import trace_agent
49
+
50
+ # Tree-sitter node types that represent an exception-handling block, per language.
51
+ CATCH_NODE_TYPES: dict[Lang, set[str]] = {
52
+ Lang.PYTHON: {"except_clause"},
53
+ Lang.JAVASCRIPT: {"catch_clause"},
54
+ Lang.TYPESCRIPT: {"catch_clause"},
55
+ Lang.JAVA: {"catch_clause"},
56
+ Lang.C_SHARP: {"catch_clause"},
57
+ Lang.CPP: {"catch_clause"},
58
+ Lang.KOTLIN: {"catch_block"},
59
+ Lang.SWIFT: {"catch_block"},
60
+ Lang.RUBY: {"rescue"},
61
+ }
62
+
63
+ # Body node types that hold the handler statements (fallback when no field name).
64
+ _BODY_TYPES = {"block", "compound_statement", "statement_block", "then", "statements"}
65
+
66
+ # Line-level heuristics for deciding whether a handler body does something useful.
67
+ _SINGLE_IDENT_RE = re.compile(r"^[a-zA-Z_]\w*$")
68
+ _CONSOLE_LOG_RE = re.compile(r"console\.(log|warn)\([^)]*\)")
69
+ _PRINT_RE = re.compile(r"print\([^)]*\)")
70
+ _P_RE = re.compile(r"p\s+[^)]+")
71
+ _TRACEBACK_RE = re.compile(r"(traceback\.print_exc|print_exc|e\.printStackTrace)")
72
+
73
+
74
+ _log = logging.getLogger("patchi.security.catch_block_auditor")
75
+
76
+
77
+ @register
78
+ class CatchBlockAuditor(BaseAgent):
79
+ """Agent for detecting empty or insufficient catch/except blocks."""
80
+
81
+ group = AgentGroup.SECURITY
82
+ name = "CatchBlockAuditor"
83
+ description = "Empty or bare catch/except blocks that swallow exceptions"
84
+
85
+ def _run(self, inp: AgentInput, result: AgentResult) -> None:
86
+ findings = []
87
+
88
+ source_patterns = [
89
+ "*.py",
90
+ "*.js",
91
+ "*.jsx",
92
+ "*.ts",
93
+ "*.tsx",
94
+ "*.java",
95
+ "*.go",
96
+ "*.rs",
97
+ "*.c",
98
+ "*.h",
99
+ "*.cpp",
100
+ "*.cxx",
101
+ "*.cc",
102
+ "*.hpp",
103
+ "*.rb",
104
+ "*.swift",
105
+ "*.kt",
106
+ "*.kts",
107
+ "*.cs",
108
+ ]
109
+
110
+ with trace_agent(self.name, inp.root) as trace:
111
+ for pattern in source_patterns:
112
+ for file_path in safe_rglob(inp.root, pattern):
113
+ if file_path.is_file():
114
+ rel_path = file_path.relative_to(inp.root).as_posix()
115
+ if not self._should_skip_file(rel_path, inp):
116
+ ext = file_path.suffix.lower()
117
+ content = self._safe_read(file_path)
118
+ if content is None:
119
+ continue
120
+ findings.extend(self._scan_catch_blocks(content, rel_path, ext))
121
+ trace.findings = len(findings)
122
+
123
+ result.status = AgentStatus.SUCCEEDED
124
+ result.findings = findings
125
+ result.data.update({"catch_block_findings": len(findings), "needs_ai": False})
126
+ return
127
+
128
+ def _should_skip_file(self, file_path: str, inp: AgentInput) -> bool:
129
+ from pathlib import PurePosixPath
130
+
131
+ restrictions = inp.config.get("restrictions", [])
132
+ for r in restrictions:
133
+ if r.get("enabled", True):
134
+ path = r["path"]
135
+ if file_path.startswith(path) or PurePosixPath(file_path).match(path):
136
+ if r["type"] == "NO_TOUCH":
137
+ return True
138
+ if r["type"] == "SCAN_ONLY" and self.__class__.__name__ == "FixAgent":
139
+ return True
140
+ return False
141
+
142
+ def _safe_read(self, path: Path) -> str | None:
143
+ try:
144
+ return path.read_text(encoding="utf-8")
145
+ except Exception as e:
146
+ _log.warning("CatchBlockAuditor._safe_read failed: %s", e)
147
+ return None
148
+
149
+ # ── Dispatch ─────────────────────────────────────────────────────────────
150
+
151
+ def _scan_catch_blocks(self, content: str, rel_path: str, ext: str) -> list[Finding]:
152
+ lang = EXTENSION_MAP.get(ext)
153
+ if lang is None:
154
+ return []
155
+
156
+ # Go and Rust have no exception-handling blocks — handle idiomatically.
157
+ if lang == Lang.GO:
158
+ return self._scan_go(content, rel_path)
159
+ if lang == Lang.RUST:
160
+ return self._scan_rust(content, rel_path)
161
+
162
+ node_types = CATCH_NODE_TYPES.get(lang)
163
+ if not node_types:
164
+ return []
165
+
166
+ tree = parse_source(content, lang)
167
+ if tree is None:
168
+ return []
169
+
170
+ findings = self._walk_catch_tree(tree.root_node, node_types, lang, rel_path)
171
+ if lang == Lang.JAVA:
172
+ findings.extend(self._scan_java_printstacktrace(content, rel_path))
173
+ return findings
174
+
175
+ # ── AST walking ──────────────────────────────────────────────────────────
176
+
177
+ def _walk_catch_tree(
178
+ self, node, node_types: set[str], lang: Lang, rel_path: str
179
+ ) -> list[Finding]:
180
+ findings: list[Finding] = []
181
+ if node.type in node_types:
182
+ spec, is_bare, body_text = self._classify_catch(node, lang)
183
+ line = node.start_point[0] + 1
184
+ if is_bare:
185
+ findings.append(
186
+ make_finding(
187
+ severity=Severity.MEDIUM,
188
+ file=rel_path,
189
+ line_start=line,
190
+ title="Bare except clause" if lang == Lang.PYTHON else "Bare catch clause",
191
+ description=(
192
+ "A catch/except handler without an exception type catches everything "
193
+ "(including control-flow exceptions). Specify the expected exception type(s) "
194
+ "to avoid swallowing critical errors."
195
+ ),
196
+ evidence=node_text(node).strip(),
197
+ cwe="CWE-755",
198
+ )
199
+ )
200
+ elif not body_text.strip():
201
+ findings.append(
202
+ make_finding(
203
+ severity=Severity.MEDIUM,
204
+ file=rel_path,
205
+ line_start=line,
206
+ title="Empty catch block",
207
+ description=(
208
+ "Catch block is empty. Exceptions are silently swallowed. "
209
+ "Add error handling, logging, or re-throw."
210
+ ),
211
+ evidence=node_text(node).strip(),
212
+ cwe="CWE-755",
213
+ )
214
+ )
215
+ elif self._is_bare_catch(body_text):
216
+ findings.append(
217
+ make_finding(
218
+ severity=Severity.LOW,
219
+ file=rel_path,
220
+ line_start=line,
221
+ title="Insufficient catch block",
222
+ description=(
223
+ f"Exception handler for '{spec}' only logs or prints without recovery. "
224
+ "Consider adding proper error handling, fallback, or re-raise."
225
+ ),
226
+ evidence=node_text(node).strip(),
227
+ cwe="CWE-755",
228
+ )
229
+ )
230
+ for child in node.children:
231
+ findings.extend(self._walk_catch_tree(child, node_types, lang, rel_path))
232
+ return findings
233
+
234
+ def _classify_catch(self, node, lang: Lang) -> tuple[str, bool, str]:
235
+ """Return (exception_spec_text, is_bare, body_text)."""
236
+ body_node = None
237
+ for field in ("body", "statements"):
238
+ b = child_by_field(node, field)
239
+ if b is not None:
240
+ body_node = b
241
+ break
242
+ if body_node is None:
243
+ for c in named_children(node):
244
+ if c.type in _BODY_TYPES:
245
+ body_node = c
246
+ break
247
+ body_text = node_text(body_node) if body_node is not None else ""
248
+ # Strip the surrounding braces so the inner statements are analysed.
249
+ stripped = body_text.strip()
250
+ if stripped.startswith("{") and stripped.endswith("}"):
251
+ inner = stripped[1:-1]
252
+ body_text = inner
253
+
254
+ if lang == Lang.PYTHON:
255
+ val = child_by_field(node, "value")
256
+ is_bare = val is None
257
+ spec = node_text(val) if val is not None else "bare except"
258
+ elif lang in (Lang.JAVASCRIPT, Lang.TYPESCRIPT):
259
+ param = child_by_field(node, "parameter")
260
+ is_bare = param is None
261
+ spec = node_text(param) if param is not None else "bare catch"
262
+ elif lang in (Lang.JAVA, Lang.C_SHARP):
263
+ cfp = None
264
+ for c in named_children(node):
265
+ if c.type in ("catch_formal_parameter", "catch_declaration"):
266
+ cfp = c
267
+ break
268
+ spec = node_text(cfp) if cfp is not None else "catch"
269
+ is_bare = False
270
+ elif lang == Lang.CPP:
271
+ params = child_by_field(node, "parameters")
272
+ ptext = node_text(params) if params is not None else ""
273
+ is_bare = ptext.strip() == "..."
274
+ spec = ptext or "catch"
275
+ elif lang == Lang.KOTLIN:
276
+ spec = node_text(node)
277
+ is_bare = False
278
+ elif lang == Lang.SWIFT:
279
+ err = child_by_field(node, "error")
280
+ is_bare = err is None
281
+ spec = node_text(err) if err is not None else "bare catch"
282
+ elif lang == Lang.RUBY:
283
+ ex = child_by_field(node, "exceptions")
284
+ is_bare = ex is None
285
+ spec = node_text(ex) if ex is not None else "bare rescue"
286
+ else:
287
+ spec = node_text(node)
288
+ is_bare = False
289
+ return spec, is_bare, body_text
290
+
291
+ def _scan_java_printstacktrace(self, content: str, rel_path: str) -> list[Finding]:
292
+ from ..brain.ast_utils import find_calls
293
+
294
+ findings: list[Finding] = []
295
+ for m in find_calls(content, Lang.JAVA, {"printStackTrace"}):
296
+ findings.append(
297
+ make_finding(
298
+ severity=Severity.LOW,
299
+ file=rel_path,
300
+ line_start=m.get("line", 0),
301
+ title="Bare printStackTrace()",
302
+ description=(
303
+ "e.printStackTrace() writes to stderr but is often lost in production. "
304
+ "Use a logging framework (SLF4J, Log4j) instead."
305
+ ),
306
+ evidence=m.get("full_text", "printStackTrace()").strip(),
307
+ cwe="CWE-755",
308
+ )
309
+ )
310
+ return findings
311
+
312
+ # ── Body usefulness analysis (text-based) ────────────────────────────────
313
+
314
+ def _is_bare_catch(self, block_body: str) -> bool:
315
+ """Check if a catch block body contains only trivial/no-op statements."""
316
+ stripped = block_body.strip().rstrip(";")
317
+ if not stripped:
318
+ return True
319
+ noop_lines = [
320
+ ln.strip().rstrip(";")
321
+ for ln in stripped.split("\n")
322
+ if ln.strip() and not ln.strip().startswith(("#", "//", "/*", "*"))
323
+ ]
324
+ if not noop_lines:
325
+ return True
326
+ for line in noop_lines:
327
+ if not self._is_noop_line(line):
328
+ return False
329
+ return True
330
+
331
+ def _is_noop_line(self, line: str) -> bool:
332
+ """Check if a line is a no-op in exception handling."""
333
+ line = line.strip().rstrip(";")
334
+ if not line:
335
+ return True
336
+ # Single identifiers (bare variable names like `error`)
337
+ if _SINGLE_IDENT_RE.match(line):
338
+ return True
339
+ # Pass, next, nil, None, null, undefined
340
+ if line in ("pass", "next", "nil", "None", "null", "undefined"):
341
+ return True
342
+ # Bare console.log/print of the error
343
+ if _CONSOLE_LOG_RE.match(line):
344
+ return True
345
+ if _PRINT_RE.match(line):
346
+ return True
347
+ if _P_RE.match(line):
348
+ return True
349
+ # Bare traceback/stack print
350
+ if _TRACEBACK_RE.match(line):
351
+ return True
352
+ return False
353
+
354
+ # ── Go / Rust (no exception-handling blocks) ─────────────────────────────
355
+
356
+ def _scan_go(self, content: str, rel_path: str) -> list[Finding]:
357
+ findings: list[Finding] = []
358
+ for assign in find_assignments(content, Lang.GO):
359
+ if assign["target"].strip() == "_":
360
+ value = assign["value"]
361
+ if value and not value.startswith('"') and not value.startswith("'"):
362
+ findings.append(
363
+ make_finding(
364
+ severity=Severity.MEDIUM,
365
+ file=rel_path,
366
+ line_start=assign["line"],
367
+ title="Error explicitly discarded with _ =",
368
+ description=(
369
+ "Error return value is explicitly discarded. "
370
+ "Check the error or use a linter to enforce error checking."
371
+ ),
372
+ evidence=assign["full_text"][:120],
373
+ cwe="CWE-755",
374
+ )
375
+ )
376
+ return findings
377
+
378
+ def _scan_rust(self, content: str, rel_path: str) -> list[Finding]:
379
+ findings: list[Finding] = []
380
+ for call in find_calls(content, Lang.RUST, {"unwrap"}):
381
+ findings.append(
382
+ make_finding(
383
+ severity=Severity.MEDIUM,
384
+ file=rel_path,
385
+ line_start=call["line"],
386
+ title="Unsafe .unwrap() call",
387
+ description=(
388
+ ".unwrap() panics on Err/None. Prefer pattern matching, "
389
+ "?, or .expect() with a descriptive message."
390
+ ),
391
+ evidence=call["full_text"][:120],
392
+ cwe="CWE-754",
393
+ )
394
+ )
395
+ return findings