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,456 @@
1
+ import logging
2
+ import os
3
+ import platform
4
+ from pathlib import Path
5
+
6
+ from rich.panel import Panel
7
+ from rich.prompt import Prompt
8
+ from rich.table import Table
9
+
10
+ from patchi.cli.console import con
11
+ from patchi.core import config as cfg
12
+ from patchi.core.constants import DeviceTier
13
+
14
+ # Import providers from key_cmd to keep them in sync
15
+ from patchi.cli.commands.key_cmd import PROVIDERS as KEY_PROVIDERS
16
+
17
+ """
18
+ `p init` - Initialize Patchi in the current project directory.
19
+
20
+ Professional first-run experience with step indicators, clean flow,
21
+ and proper OS-specific alias installation.
22
+ """
23
+
24
+
25
+ try:
26
+ from patchi.cli.logo import draw as draw_logo
27
+ except ImportError:
28
+
29
+ def draw_logo(*a, **kw): # noqa: ARG001
30
+ return None
31
+
32
+
33
+ STEP_DONE = "[#4ADE80] ok [/#4ADE80]"
34
+ STEP_ARROW = "[#C8621A] >> [/#C8621A]"
35
+ STEP_PENDING = "[dim] ... [/dim]"
36
+
37
+
38
+ _log = logging.getLogger("patchi.cli.init")
39
+
40
+
41
+ def run(no_logo: bool = False) -> None:
42
+ """Entry point for `p init` / `patchi init`."""
43
+
44
+ draw_logo(con, skip=no_logo)
45
+
46
+ con.print()
47
+ con.print(
48
+ Panel.fit(
49
+ "[bold #F2EDD6]Project Initializer[/bold #F2EDD6]\n",
50
+ border_style="#C8621A",
51
+ subtitle="[dim]Step 1 of 4[/dim]",
52
+ )
53
+ )
54
+ con.print()
55
+
56
+ project_root = Path.cwd()
57
+
58
+ # ── Step 1: Detect hardware ────────────────────────────────────────────────
59
+ con.print(f"{STEP_ARROW} [bold]Detecting hardware...[/bold]")
60
+ tier = _detect_device_tier()
61
+ con.print(f"{STEP_DONE} {tier.value.upper()} tier [dim]({_tier_description(tier)})[/dim]")
62
+ con.print()
63
+
64
+ # ── Step 2: Create project structure ───────────────────────────────────────
65
+ con.print(f"{STEP_ARROW} [bold]Creating project structure...[/bold]")
66
+ already_exists = (project_root / ".patchi").exists()
67
+ cfg.init_project(project_root, device_tier=tier)
68
+
69
+ if already_exists:
70
+ con.print(f"{STEP_DONE} Existing config merged with defaults")
71
+ else:
72
+ con.print(f"{STEP_DONE} Created [bold].patchi/[/bold] with config, memory, and queue files")
73
+
74
+ _update_gitignore(project_root)
75
+ con.print()
76
+
77
+ # ── Step 3: Shell alias ────────────────────────────────────────────────────
78
+ con.print(f"{STEP_ARROW} [bold]Shell alias...[/bold]")
79
+ alias_result = _install_alias()
80
+ if alias_result["success"]:
81
+ if alias_result.get("already"):
82
+ con.print(f"{STEP_DONE} [bold]p[/bold] alias already installed")
83
+ else:
84
+ con.print(f"{STEP_DONE} [bold]p[/bold] alias written to {alias_result['file']}")
85
+ con.print(f" [dim]Restart your terminal or run: source {alias_result['file']}[/dim]")
86
+ else:
87
+ con.print(f"[yellow] warn Could not install alias: {alias_result['reason']}[/yellow]")
88
+ con.print(" [dim]Add manually: [bold]alias p='patchi'[/bold][/dim]")
89
+ con.print()
90
+
91
+ # ── Step 4: AI setup ───────────────────────────────────────────────────────
92
+ con.print(f"{STEP_ARROW} [bold]AI configuration...[/bold]")
93
+ con.print()
94
+ con.print(
95
+ Panel(
96
+ "[bold]Patchi needs an AI model to generate fixes.[/bold]\n",
97
+ title="[bold #C8621A]AI Setup[/bold #C8621A]",
98
+ border_style="#C8621A",
99
+ padding=(1, 2),
100
+ )
101
+ )
102
+ con.print()
103
+
104
+ # Show provider options dynamically from KEY_PROVIDERS
105
+ con.print(" [bold]Choose AI provider:[/bold]")
106
+ con.print()
107
+ for i, p in enumerate(KEY_PROVIDERS, 1):
108
+ con.print(f" [bold]{i}[/bold] {p['name']:<14} [dim]{p['docs']}[/dim]")
109
+ con.print()
110
+
111
+ try:
112
+ choice = Prompt.ask(" Provider number or name", default="1")
113
+ except (EOFError, OSError):
114
+ choice = "1"
115
+ con.print(" [dim]Non-interactive mode — using first provider (Groq)[/dim]")
116
+
117
+ # Handle provider choice
118
+ provider_data = None
119
+ if choice.isdigit():
120
+ idx = int(choice) - 1
121
+ if 0 <= idx < len(KEY_PROVIDERS):
122
+ provider_data = KEY_PROVIDERS[idx]
123
+ else:
124
+ # Find by name (case-insensitive)
125
+ for p in KEY_PROVIDERS:
126
+ if p["name"].lower() == choice.lower():
127
+ provider_data = p
128
+ break
129
+
130
+ if not provider_data:
131
+ con.print(f" [yellow]Unknown provider: {choice!r}, using Custom[/yellow]")
132
+ provider_data = KEY_PROVIDERS[-1] # Custom
133
+
134
+ if provider_data["name"] == "Custom":
135
+ # Use the same flow as key_cmd for custom
136
+ _setup_custom_provider(project_root)
137
+ elif provider_data["name"] == "Ollama":
138
+ _setup_local_model(project_root)
139
+ else:
140
+ _setup_known_provider(project_root, provider_data)
141
+
142
+ con.print()
143
+
144
+ # Mark onboarding as complete (M-01)
145
+ try:
146
+ from patchi.core import config as _cfg
147
+
148
+ _c = _cfg.load(project_root)
149
+ _c["onboarding_complete"] = True
150
+ _cfg.save(_c, project_root)
151
+ except Exception as e:
152
+ _log.warning("run failed: %s", e)
153
+
154
+ # ── Done ───────────────────────────────────────────────────────────────────
155
+ _show_complete_panel(project_root)
156
+
157
+
158
+ def _show_complete_panel(root: Path) -> None:
159
+ """Show the completion panel with next steps."""
160
+ # Build a status table
161
+ table = Table(show_header=False, box=None, pad_edge=False, padding=(0, 2))
162
+ table.add_column("Key", style="bold #F2EDD6", width=18)
163
+ table.add_column("Value", style="#B8A898")
164
+
165
+ table.add_row("Project", str(root))
166
+ table.add_row("Config", ".patchi/config.json")
167
+
168
+ try:
169
+ config = cfg.load(root)
170
+ mode = config.get("mode", "confirm")
171
+ table.add_row("Mode", mode)
172
+
173
+ ai_cfg = config.get("ai", {})
174
+ if ai_cfg.get("local_model_name"):
175
+ table.add_row("AI", f"Ollama ({ai_cfg['local_model_name']})")
176
+ elif ai_cfg.get("keys"):
177
+ count = len(ai_cfg["keys"])
178
+ table.add_row("AI", f"{count} API key(s) configured")
179
+ else:
180
+ table.add_row("AI", "[yellow]Not configured[/yellow]")
181
+ except Exception as e:
182
+ _log.warning("_show_complete_panel failed: %s", e)
183
+
184
+ tier = _detect_device_tier()
185
+ table.add_row("Hardware", f"{tier.value.upper()} tier")
186
+
187
+ con.print(
188
+ Panel(
189
+ table,
190
+ title="[bold #4ADE80]Patchi is ready[/bold #4ADE80]",
191
+ border_style="#4ADE80",
192
+ padding=(0, 1),
193
+ )
194
+ )
195
+ con.print()
196
+
197
+ con.print("[bold #F2EDD6]Next steps:[/bold #F2EDD6]")
198
+ con.print(" [bold]p scan[/bold] [dim]Scan your project for issues[/dim]")
199
+ con.print(" [bold]p scan --deep[/bold] [dim]Scan + AI analysis (uses tokens)[/dim]")
200
+ con.print(" [bold]p web[/bold] [dim]Open the visual dashboard[/dim]")
201
+ con.print(" [bold]p doctor[/bold] [dim]Validate setup and dependencies[/dim]")
202
+ con.print()
203
+
204
+
205
+ # ── Alias install (cross-platform) ───────────────────────────────────────────
206
+
207
+
208
+ def _install_alias() -> dict:
209
+ """Install `p` as a short alias for `patchi`. Cross-platform."""
210
+ system = platform.system()
211
+ home = Path.home()
212
+
213
+ if system == "Windows":
214
+ return _install_alias_windows(home)
215
+ else:
216
+ return _install_alias_unix(home)
217
+
218
+
219
+ def _install_alias_windows(home: Path) -> dict:
220
+ """Windows: create a batch file wrapper in a PATH-friendly location."""
221
+ scripts_dir = home / "patchi_scripts"
222
+ scripts_dir.mkdir(exist_ok=True)
223
+
224
+ bat_file = scripts_dir / "p.bat"
225
+ if bat_file.exists():
226
+ return {"success": True, "file": str(bat_file), "already": True}
227
+
228
+ try:
229
+ bat_file.write_text(
230
+ "@echo off\npatchi %*\n",
231
+ encoding="utf-8",
232
+ )
233
+
234
+ # Check if already in PATH
235
+ path_env = os.environ.get("PATH", "")
236
+ if str(scripts_dir) not in path_env:
237
+ con.print(f" [dim]Add to PATH: {scripts_dir}[/dim]")
238
+ con.print(f' [dim]Or run: [bold]setx PATH "%PATH%;{scripts_dir}"[/bold][/dim]')
239
+
240
+ return {"success": True, "file": str(bat_file)}
241
+ except OSError as e:
242
+ return {"success": False, "file": str(bat_file), "reason": str(e)}
243
+
244
+
245
+ def _install_alias_unix(home: Path) -> dict:
246
+ """Unix: write alias to .bashrc or .zshrc."""
247
+ shell = os.environ.get("SHELL", "")
248
+ if "zsh" in shell:
249
+ rc_file = home / ".zshrc"
250
+ else:
251
+ rc_file = home / ".bashrc"
252
+
253
+ alias_line = "alias p='patchi' # added by patchi init\n"
254
+ try:
255
+ if rc_file.exists():
256
+ content = rc_file.read_text(encoding="utf-8")
257
+ if "alias p='patchi'" in content or 'alias p="patchi"' in content:
258
+ return {"success": True, "file": str(rc_file), "already": True}
259
+
260
+ with rc_file.open("a", encoding="utf-8") as f:
261
+ f.write(f"\n{alias_line}")
262
+
263
+ return {"success": True, "file": str(rc_file)}
264
+ except OSError as e:
265
+ return {"success": False, "file": str(rc_file), "reason": str(e)}
266
+
267
+
268
+ # ── AI setup helpers ───────────────────────────────────────────────────────────
269
+
270
+
271
+ def _setup_local_model(root: Path) -> None:
272
+ model_name = Prompt.ask(
273
+ " Ollama model name",
274
+ default="llama3.2",
275
+ )
276
+ cfg.set_value("ai.local_model_name", model_name, root)
277
+ con.print(
278
+ f" [dim]Model set to [bold]{model_name}[/bold]. Make sure Ollama is running.[/dim]"
279
+ )
280
+
281
+
282
+ def _setup_custom_provider(root: Path) -> None:
283
+ """Set up a custom OpenAI-compatible provider (same as key_cmd flow)."""
284
+ con.print()
285
+ con.print(" [dim]Enter your provider's OpenAI-compatible API details.[/dim]")
286
+
287
+ provider_name = Prompt.ask(" Provider name")
288
+ if not provider_name.strip():
289
+ con.print("[red]Provider name is required.[/red]")
290
+ return
291
+
292
+ base_url = Prompt.ask(" Base URL", default="https://api.openai.com/v1")
293
+ if not base_url.strip():
294
+ con.print("[red]Base URL is required.[/red]")
295
+ return
296
+
297
+ model = Prompt.ask(" Model name")
298
+ if not model.strip():
299
+ con.print("[red]Model name is required.[/red]")
300
+ return
301
+
302
+ format_choices = ["openai", "anthropic", "google", "cohere"]
303
+ fmt = Prompt.ask(" API format", choices=format_choices, default="openai")
304
+
305
+ # Use secure key input that works in PowerShell
306
+ api_key = _secure_key_input(" Paste your API key")
307
+ if not api_key.strip():
308
+ con.print("[red]No key entered.[/red]")
309
+ return
310
+
311
+ nickname = Prompt.ask(" Nickname for this key", default=provider_name)
312
+
313
+ _store_key(
314
+ root, provider=provider_name, base_url=base_url, model=model, api_key=api_key, fmt=fmt,
315
+ nickname=nickname,
316
+ )
317
+
318
+
319
+ def _setup_known_provider(root: Path, provider_data: dict) -> None:
320
+ """Set up a known provider from KEY_PROVIDERS list."""
321
+ api_key = _secure_key_input(f" Paste your {provider_data['name']} API key")
322
+ if not api_key.strip():
323
+ con.print("[red]No key entered.[/red]")
324
+ return
325
+
326
+ nickname = Prompt.ask(" Nickname for this key", default=provider_data["name"])
327
+
328
+ _store_key(
329
+ root,
330
+ provider=provider_data["name"],
331
+ base_url=provider_data["base"],
332
+ model=provider_data["model"],
333
+ api_key=api_key,
334
+ fmt=provider_data["format"],
335
+ nickname=nickname,
336
+ )
337
+
338
+
339
+ def _secure_key_input(prompt: str) -> str:
340
+ """
341
+ Securely read an API key from stdin, with support for pasting in PowerShell.
342
+ """
343
+ try:
344
+ import getpass
345
+ return getpass.getpass(prompt + " ")
346
+ except Exception:
347
+ pass
348
+
349
+ # Fallback: use rich's Prompt but without password masking
350
+ # This allows pasting in PowerShell - the key is stored securely in .env anyway
351
+ from rich.prompt import Prompt
352
+ return Prompt.ask(prompt)
353
+
354
+
355
+ def _store_key(
356
+ root: Path,
357
+ provider: str,
358
+ base_url: str,
359
+ model: str,
360
+ api_key: str,
361
+ fmt: str = "openai",
362
+ nickname: str | None = None,
363
+ ) -> None:
364
+ """Store an API key in config and keys.json."""
365
+ nickname = nickname or provider
366
+ env_var = f"PATCHI_KEY_{nickname.upper().replace(' ', '_')}"
367
+
368
+ existing_keys: list = cfg.load(root).get("ai", {}).get("keys", [])
369
+ existing_keys.append(
370
+ {
371
+ "provider": provider,
372
+ "nickname": nickname,
373
+ "env_var": env_var,
374
+ "base_url": base_url,
375
+ "model": model,
376
+ "format": fmt,
377
+ "status": "untested",
378
+ }
379
+ )
380
+
381
+ # Store key in keys.json
382
+ keys_file = root / ".patchi" / "keys.json"
383
+ import json
384
+
385
+ data = {}
386
+ if keys_file.exists():
387
+ try:
388
+ data = json.loads(keys_file.read_text(encoding="utf-8"))
389
+ except Exception as e:
390
+ _log.warning("_store_key failed: %s", e)
391
+ data = {}
392
+ data[env_var] = api_key
393
+ keys_file.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
394
+
395
+ # Update gitignore
396
+ _ensure_gitignore_entry(root, ".patchi/keys.json", "# Patchi key storage")
397
+
398
+ cfg.set_value("ai.keys", existing_keys, root)
399
+ con.print(f" [dim]Env var: {env_var}[/dim]")
400
+ con.print(" [dim]Key stored. Never leaves your machine.[/dim]")
401
+
402
+
403
+ # ── Gitignore helpers ──────────────────────────────────────────────────────────
404
+
405
+
406
+ def _update_gitignore(project_root: Path) -> None:
407
+ """Add .patchi/ entries to .gitignore if not already present."""
408
+ entries = [".patchi/", ".patchi/.env", ".patchi/keys.json"]
409
+ comment = "# Patchi local config"
410
+ _ensure_gitignore(project_root, entries, comment)
411
+
412
+
413
+ def _ensure_gitignore(project_root: Path, entries: list[str], comment: str) -> None:
414
+ gitignore = project_root / ".gitignore"
415
+ if gitignore.exists():
416
+ content = gitignore.read_text(encoding="utf-8")
417
+ missing = [e for e in entries if e not in content]
418
+ if missing:
419
+ with gitignore.open("a", encoding="utf-8") as f:
420
+ f.write(f"\n{comment}\n")
421
+ for entry in missing:
422
+ f.write(f"{entry}\n")
423
+ else:
424
+ with gitignore.open("w", encoding="utf-8") as f:
425
+ f.write(f"{comment}\n")
426
+ for entry in entries:
427
+ f.write(f"{entry}\n")
428
+
429
+
430
+ def _ensure_gitignore_entry(project_root: Path, entry: str, comment: str) -> None:
431
+ _ensure_gitignore(project_root, [entry], comment)
432
+
433
+
434
+ # ── Device tier detection ──────────────────────────────────────────────────────
435
+
436
+
437
+ def _detect_device_tier() -> DeviceTier:
438
+ try:
439
+ import psutil
440
+
441
+ ram_gb = psutil.virtual_memory().total / (1024**3)
442
+ if ram_gb < 4:
443
+ return DeviceTier.LOW
444
+ if ram_gb < 16:
445
+ return DeviceTier.MID
446
+ return DeviceTier.HIGH
447
+ except ImportError:
448
+ return DeviceTier.MID
449
+
450
+
451
+ def _tier_description(tier: DeviceTier) -> str:
452
+ return {
453
+ DeviceTier.LOW: "< 4GB RAM, single queue mode",
454
+ DeviceTier.MID: "4-16GB RAM, multi queue mode",
455
+ DeviceTier.HIGH: "16GB+ RAM, full parallelism",
456
+ }[tier]