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,144 @@
1
+ """
2
+ AST utilities — generic tree-sitter node helpers.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ import ast as _py_ast
8
+ import logging
9
+ from typing import Any
10
+
11
+ from patchi.core.brain.languages import Lang, get_parser
12
+
13
+ _log = logging.getLogger("patchi.brain.helpers")
14
+
15
+
16
+ def _py_call_name(node: _py_ast.Call) -> str:
17
+ """Full dotted name of a Python ``Call`` node's function.
18
+
19
+ Single source of truth shared by ``calls.find_calls`` and the cached
20
+ single-pass scan (``scan.scan_python``) so name resolution can never
21
+ drift between the two.
22
+ """
23
+ if isinstance(node.func, _py_ast.Name):
24
+ return node.func.id
25
+ if isinstance(node.func, _py_ast.Attribute):
26
+ parts = []
27
+ cur = node.func
28
+ while isinstance(cur, _py_ast.Attribute):
29
+ parts.append(cur.attr)
30
+ cur = cur.value
31
+ if isinstance(cur, _py_ast.Name):
32
+ parts.append(cur.id)
33
+ return ".".join(reversed(parts))
34
+ return ""
35
+
36
+
37
+ def _py_assign_target_name(node: _py_ast.AST) -> str:
38
+ """Dotted name of a Python assignment target.
39
+
40
+ Single source of truth shared by ``assignments.find_assignments`` and the
41
+ cached single-pass scan.
42
+ """
43
+ if isinstance(node, _py_ast.Name):
44
+ return node.id
45
+ if isinstance(node, _py_ast.Attribute):
46
+ parts = []
47
+ cur = node
48
+ while isinstance(cur, _py_ast.Attribute):
49
+ parts.append(cur.attr)
50
+ cur = cur.value
51
+ if isinstance(cur, _py_ast.Name):
52
+ parts.append(cur.id)
53
+ return ".".join(reversed(parts))
54
+ return ""
55
+
56
+
57
+ def parse_source(content: str, lang: Lang) -> Any | None:
58
+ """Parse `content` with the tree-sitter parser for `lang`.
59
+
60
+ Returns the parse tree (with `.root_node`) or None if no parser is
61
+ available or parsing fails. All languages use tree-sitter so callers
62
+ can walk a uniform node interface.
63
+ """
64
+ parser = get_parser(lang)
65
+ if not parser:
66
+ return None
67
+ try:
68
+ return parser.parse(content.encode("utf-8"))
69
+ except Exception as e:
70
+ _log.debug("parse_source failed: %s", e)
71
+ return None
72
+
73
+
74
+ def node_text(node: Any) -> str:
75
+ try:
76
+ raw = getattr(node, "text", b"")
77
+ if isinstance(raw, bytes):
78
+ return raw.decode("utf-8", errors="replace")
79
+ return str(raw)
80
+ except Exception as e:
81
+ _log.debug("node_text failed: %s", e)
82
+ return ""
83
+
84
+
85
+ def child_by_field(node: Any, field: str) -> Any | None:
86
+ if hasattr(node, "child_by_field_name"):
87
+ return node.child_by_field_name(field)
88
+ return None
89
+
90
+
91
+ def children(node: Any) -> list[Any]:
92
+ try:
93
+ return list(node.children) if hasattr(node, "children") else []
94
+ except Exception as e:
95
+ _log.debug("children failed: %s", e)
96
+ return []
97
+
98
+
99
+ def named_children(node: Any) -> list[Any]:
100
+ try:
101
+ return list(node.named_children) if hasattr(node, "named_children") else []
102
+ except Exception as e:
103
+ _log.debug("named_children failed: %s", e)
104
+ return []
105
+
106
+
107
+ def _leaf_name(fn: str) -> str:
108
+ """Extract the leaf symbol from a possibly dotted / scoped name.
109
+
110
+ Handles both `.` (Python, JS, Java) and `::` (Rust, C++) separators.
111
+ """
112
+ for sep in (".", "::"):
113
+ if sep in fn:
114
+ return fn.split(sep)[-1]
115
+ return fn
116
+
117
+
118
+ def get_call_arg(call_full_text: str, position: int = 0) -> str:
119
+ """Extract the positional argument at `position` from a call text."""
120
+ try:
121
+ paren = call_full_text.index("(")
122
+ rest = call_full_text[paren + 1 :]
123
+ depth = 0
124
+ arg_start = 0
125
+ arg_idx = 0
126
+ for i, ch in enumerate(rest):
127
+ if ch in ("(", "[", "{"):
128
+ depth += 1
129
+ elif ch in (")", "]", "}"):
130
+ depth -= 1
131
+ if depth < 0:
132
+ if arg_idx == position:
133
+ return rest[arg_start:i].strip()
134
+ break
135
+ elif ch == "," and depth == 0:
136
+ if arg_idx == position:
137
+ return rest[arg_start:i].strip()
138
+ arg_start = i + 1
139
+ arg_idx += 1
140
+ if arg_idx == position:
141
+ return rest[arg_start:].strip().rstrip(")")
142
+ except (ValueError, IndexError):
143
+ pass
144
+ return ""
@@ -0,0 +1,169 @@
1
+ """
2
+ AST utilities — import statement finding across languages.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ import ast as _py_ast
8
+ import logging
9
+ from typing import Any
10
+
11
+ from patchi.core.brain.languages import Lang, get_parser
12
+
13
+ from .config import IMPORT_NODE_TYPES
14
+ from .helpers import child_by_field, children, node_text
15
+
16
+ _log = logging.getLogger("patchi.brain.imports")
17
+
18
+
19
+ def find_imports(content: str, lang: Lang, names: set[str]) -> list[dict]:
20
+ """
21
+ Find all import statements matching one of `names`.
22
+ Returns list of dicts with keys: name, line, full_text.
23
+ """
24
+ if lang == Lang.PYTHON:
25
+ return _find_imports_python(content, names)
26
+ parser = get_parser(lang)
27
+ if not parser:
28
+ return []
29
+ try:
30
+ tree = parser.parse(content.encode("utf-8"))
31
+ except Exception as e:
32
+ _log.warning("find_imports failed: %s", e)
33
+ return []
34
+ import_types = IMPORT_NODE_TYPES.get(lang, set())
35
+ results: list[dict] = []
36
+ _walk_imports(tree.root_node, import_types, names, results, lang)
37
+ return results
38
+
39
+
40
+ def _find_imports_python(content: str, names: set[str]) -> list[dict]:
41
+ results: list[dict] = []
42
+ try:
43
+ tree = _py_ast.parse(content)
44
+ except SyntaxError:
45
+ return results
46
+ for node in _py_ast.walk(tree):
47
+ if isinstance(node, _py_ast.Import):
48
+ for alias in node.names:
49
+ if alias.name in names:
50
+ results.append(
51
+ {
52
+ "name": alias.name,
53
+ "line": getattr(node, "lineno", 0),
54
+ "full_text": _ast_text(node, content),
55
+ }
56
+ )
57
+ elif isinstance(node, _py_ast.ImportFrom):
58
+ if node.module and node.module in names:
59
+ results.append(
60
+ {
61
+ "name": node.module,
62
+ "line": getattr(node, "lineno", 0),
63
+ "full_text": _ast_text(node, content),
64
+ }
65
+ )
66
+ return results
67
+
68
+
69
+ def _ast_text(node: _py_ast.AST, source: str) -> str:
70
+ try:
71
+ lines = source.splitlines()
72
+ start = getattr(node, "lineno", 1) - 1
73
+ end = getattr(node, "end_lineno", start + 1) - 1
74
+ return "\n".join(lines[start : end + 1])
75
+ except Exception as e:
76
+ _log.debug("_ast_text failed: %s", e)
77
+ return ""
78
+
79
+
80
+ def _walk_imports(
81
+ node: Any, import_types: set[str], names: set[str], results: list[dict], lang: Lang
82
+ ) -> None:
83
+ try:
84
+ ntype = node.type if hasattr(node, "type") else ""
85
+ except Exception as e:
86
+ _log.warning("_walk_imports failed: %s", e)
87
+ return
88
+
89
+ if ntype in import_types:
90
+ imp_name = _extract_import_name(node, lang)
91
+ if imp_name and any(n in imp_name for n in names):
92
+ try:
93
+ line = node.start_point[0] + 1 if node.start_point else 0
94
+ except Exception as e:
95
+ _log.warning("_walk_imports failed: %s", e)
96
+ line = 0
97
+ results.append(
98
+ {
99
+ "name": imp_name,
100
+ "line": line,
101
+ "full_text": node_text(node),
102
+ }
103
+ )
104
+
105
+ for child in children(node):
106
+ _walk_imports(child, import_types, names, results, lang)
107
+
108
+
109
+ def _extract_import_name(node: Any, lang: Lang) -> str:
110
+ if lang in (Lang.JAVASCRIPT, Lang.TYPESCRIPT):
111
+ source = child_by_field(node, "source")
112
+ if source:
113
+ return node_text(source).strip("\"'")
114
+ return ""
115
+ if lang in (Lang.RUST, Lang.JAVA, Lang.GO, Lang.SWIFT, Lang.C_SHARP, Lang.KOTLIN, Lang.DART):
116
+ # Try named fields first
117
+ src = (
118
+ child_by_field(node, "source")
119
+ or child_by_field(node, "name")
120
+ or child_by_field(node, "alias")
121
+ )
122
+ if src:
123
+ return node_text(src).strip("\"'<>")
124
+ # Walk children for identifier / scoped_identifier / string
125
+ for child in children(node):
126
+ ct = child.type
127
+ if ct == "scoped_identifier":
128
+ return node_text(child)
129
+ if ct in ("identifier", "name"):
130
+ return node_text(child)
131
+ if lang == Lang.GO and ct == "import_spec":
132
+ for c2 in children(child):
133
+ if c2.type == "interpreted_string_literal":
134
+ return node_text(c2).strip('"')
135
+ if lang in (Lang.C_SHARP,) and ct == "string_literal":
136
+ return node_text(child).strip("\"'")
137
+ if lang == Lang.C_SHARP and ct == "alias_qualified_name":
138
+ for c2 in children(child):
139
+ if c2.type == "identifier":
140
+ return node_text(c2)
141
+ return ""
142
+ if lang in (Lang.C, Lang.CPP):
143
+ for child in children(node):
144
+ if child.type == "string_literal":
145
+ return node_text(child).strip('"<>')
146
+ return ""
147
+ if lang == Lang.RUBY:
148
+ for child in children(node):
149
+ if child.type in ("string", "simple_symbol"):
150
+ return node_text(child).strip("\"':")
151
+ if child.type == "argument_list":
152
+ for c2 in children(child):
153
+ if c2.type in ("string", "simple_symbol"):
154
+ return node_text(c2).strip("\"':")
155
+ return ""
156
+ if lang == Lang.PHP:
157
+ name_node = child_by_field(node, "name")
158
+ if name_node:
159
+ return node_text(name_node)
160
+ for child in children(node):
161
+ ct = child.type
162
+ if ct == "namespace_use_clause":
163
+ for c2 in children(child):
164
+ if c2.type == "qualified_name":
165
+ return node_text(c2)
166
+ if ct in ("namespace_name", "name", "qualified_name"):
167
+ return node_text(child)
168
+ return ""
169
+ return ""
@@ -0,0 +1,143 @@
1
+ """
2
+ AST scanning utilities for Patchi.
3
+ Provides tree-sitter based code scanning capabilities.
4
+ """
5
+
6
+ import logging
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ def _slice(node: Any, source: str) -> str:
14
+ """Extract source code slice for a tree-sitter node."""
15
+ try:
16
+ return source[node.start_byte : node.end_byte]
17
+ except Exception:
18
+ return ""
19
+
20
+
21
+ def scan_python(
22
+ source: str,
23
+ file_path: Path,
24
+ ) -> dict[str, Any]:
25
+ """
26
+ Scan Python source code and extract structured information.
27
+
28
+ Returns a dictionary with:
29
+ - functions: list of function definitions
30
+ - classes: list of class definitions
31
+ - imports: list of imports
32
+ - calls: function/method calls
33
+ """
34
+ try:
35
+ import ast
36
+ except ImportError:
37
+ logger.warning("ast module not available")
38
+ return {"functions": [], "classes": [], "imports": [], "calls": []}
39
+
40
+ try:
41
+ tree = ast.parse(source)
42
+ except SyntaxError as e:
43
+ logger.warning(f"Syntax error in {file_path}: {e}")
44
+ return {"functions": [], "classes": [], "imports": [], "calls": []}
45
+
46
+ functions = []
47
+ classes = []
48
+ imports = []
49
+ calls = []
50
+
51
+ for node in ast.walk(tree):
52
+ if isinstance(node, ast.FunctionDef):
53
+ functions.append(
54
+ {
55
+ "name": node.name,
56
+ "line": node.lineno,
57
+ "end_line": getattr(node, "end_lineno", node.lineno),
58
+ "args": [a.arg for a in node.args.args],
59
+ "returns": ast.unparse(node.returns) if node.returns else None,
60
+ }
61
+ )
62
+ elif isinstance(node, ast.ClassDef):
63
+ classes.append(
64
+ {
65
+ "name": node.name,
66
+ "line": node.lineno,
67
+ "end_line": getattr(node, "end_lineno", node.lineno),
68
+ "bases": [ast.unparse(b) for b in node.bases],
69
+ }
70
+ )
71
+ elif isinstance(node, ast.Import):
72
+ for alias in node.names:
73
+ imports.append(
74
+ {
75
+ "name": alias.name,
76
+ "alias": alias.asname,
77
+ "line": node.lineno,
78
+ }
79
+ )
80
+ elif isinstance(node, ast.ImportFrom):
81
+ for alias in node.names:
82
+ imports.append(
83
+ {
84
+ "name": f"{node.module}.{alias.name}" if node.module else alias.name,
85
+ "alias": alias.asname,
86
+ "line": node.lineno,
87
+ }
88
+ )
89
+ elif isinstance(node, ast.Call):
90
+ # Full dotted name via the shared helper (single source of truth
91
+ # with calls.find_calls) — leaf-only names broke deep dotted
92
+ # matching like a.b.c.execute().
93
+ from .helpers import _py_call_name
94
+
95
+ func_name = _py_call_name(node)
96
+ calls.append(
97
+ {
98
+ "function": func_name,
99
+ "line": node.lineno,
100
+ }
101
+ )
102
+
103
+ return {
104
+ "functions": functions,
105
+ "classes": classes,
106
+ "imports": imports,
107
+ "calls": calls,
108
+ }
109
+
110
+
111
+ def scan_generic(source: str, file_path: Path) -> dict[str, Any]:
112
+ """
113
+ Generic scanner for non-Python files.
114
+ Returns basic structural information.
115
+ """
116
+ return {
117
+ "functions": [],
118
+ "classes": [],
119
+ "imports": [],
120
+ "calls": [],
121
+ }
122
+
123
+
124
+ def scan_file(file_path: Path) -> dict[str, Any]:
125
+ """
126
+ Scan a file and return structured information.
127
+ """
128
+ try:
129
+ source = file_path.read_text(encoding="utf-8", errors="ignore")
130
+ except Exception as e:
131
+ logger.warning(f"Failed to read {file_path}: {e}")
132
+ return {"functions": [], "classes": [], "imports": [], "calls": []}
133
+
134
+ suffix = file_path.suffix.lower()
135
+ if suffix == ".py":
136
+ return scan_python(source, file_path)
137
+ else:
138
+ return scan_generic(source, file_path)
139
+
140
+
141
+ def scan_python_file(file_path: Path) -> dict[str, Any]:
142
+ """Convenience function to scan a Python file."""
143
+ return scan_python(file_path.read_text(encoding="utf-8"), file_path)