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,444 @@
1
+ """
2
+ Patch data model and risk scoring for Patchi.
3
+
4
+ A Patch is a proposed code change produced by a fix agent.
5
+ It is NOT applied automatically — it goes through the risk gate first.
6
+
7
+ Patch lifecycle:
8
+ proposed → [risk gate] → pending | auto_applied | rejected
9
+ pending → accepted (user) → applying → applied | rolled_back
10
+ applied → undone → rolled_back
11
+
12
+ Risk score (0–100):
13
+ 0–30 LOW safe to auto-apply in AUTO mode
14
+ 31–60 MEDIUM logic changes — require review in CONFIRM mode
15
+ 61–100 HIGH auth, payments, data — always ask regardless of mode
16
+
17
+ Risk factors (additive):
18
+ +10 each file beyond the first (multi-file patch)
19
+ +8 each function signature changed
20
+ +5 per 20 lines changed (capped at +30)
21
+ +25 touches auth/payment/session/token files or routes
22
+ +20 touches database schema or migration
23
+ +15 changes error handling (try/except/catch blocks modified)
24
+ +10 blast radius > 5 (many files depend on changed file)
25
+ +5 blast radius > 2
26
+
27
+ Confidence score (0–100):
28
+ Starts at 100. Deductions:
29
+ -20 fix agent had < 80% certainty about root cause
30
+ -15 file parse had errors
31
+ -10 test suite absent for this file
32
+ -10 fix modifies a file with no test coverage
33
+ -5 multiple possible interpretations of the issue
34
+ """
35
+
36
+ from __future__ import annotations
37
+
38
+ import difflib
39
+ import json
40
+ import logging
41
+ import re as _re
42
+ import uuid
43
+ from dataclasses import dataclass, field
44
+ from datetime import UTC, datetime
45
+ from enum import StrEnum
46
+ from pathlib import Path
47
+
48
+ _log = logging.getLogger("patchi.core.fix.patch")
49
+
50
+
51
+ # ── Helpers (must be defined before class field defaults reference them) ────────
52
+
53
+
54
+ def _now() -> str:
55
+ return datetime.now(UTC).isoformat()
56
+
57
+
58
+ def _compute_diff(path: str, original: str, proposed: str) -> str:
59
+ lines_a = original.splitlines(keepends=True)
60
+ lines_b = proposed.splitlines(keepends=True)
61
+ return "".join(
62
+ difflib.unified_diff(
63
+ lines_a,
64
+ lines_b,
65
+ fromfile=f"a/{path}",
66
+ tofile=f"b/{path}",
67
+ )
68
+ )
69
+
70
+
71
+ # ── Patch states ───────────────────────────────────────────────────────────────
72
+
73
+
74
+ class PatchState(StrEnum):
75
+ PROPOSED = "proposed" # created by fix agent, not yet gated
76
+ PENDING = "pending" # passed risk gate, waiting for user
77
+ AUTO_APPLIED = "auto_applied" # applied automatically (AUTO/AUTOPILOT mode, low risk)
78
+ APPLYING = "applying" # currently being written to disk
79
+ APPLIED = "applied" # written to disk, tests passed
80
+ FAILED = "failed" # applied but tests failed, rolled back
81
+ ROLLED_BACK = "rolled_back" # reverted via snapshot
82
+ REJECTED = "rejected" # user explicitly rejected
83
+ UNDONE = "undone" # user undone after apply
84
+
85
+
86
+ # ── Patch types ────────────────────────────────────────────────────────────────
87
+
88
+
89
+ class PatchType(StrEnum):
90
+ BUG_FIX = "bug_fix"
91
+ SECURITY = "security"
92
+ DEAD_CODE = "dead_code"
93
+ DEPENDENCY = "dependency"
94
+ ENV_FIX = "env_fix"
95
+ TYPE_FIX = "type_fix"
96
+ REFACTOR = "refactor"
97
+ TEST_ADD = "test_add"
98
+ CONFIG = "config"
99
+ PERF = "perf"
100
+
101
+
102
+ # ── File change ────────────────────────────────────────────────────────────────
103
+
104
+
105
+ @dataclass
106
+ class FileChange:
107
+ """A single file's change within a patch."""
108
+
109
+ path: str # relative path
110
+ original: str # original content (before fix)
111
+ proposed: str # proposed content (after fix)
112
+ diff: str = "" # unified diff (computed on creation)
113
+
114
+ def __post_init__(self) -> None:
115
+ if not self.diff:
116
+ self.diff = _compute_diff(self.path, self.original, self.proposed)
117
+
118
+ @property
119
+ def lines_added(self) -> int:
120
+ return sum(
121
+ 1
122
+ for line in self.diff.splitlines()
123
+ if line.startswith("+") and not line.startswith("+++")
124
+ )
125
+
126
+ @property
127
+ def lines_removed(self) -> int:
128
+ return sum(
129
+ 1
130
+ for line in self.diff.splitlines()
131
+ if line.startswith("-") and not line.startswith("---")
132
+ )
133
+
134
+ @property
135
+ def lines_changed(self) -> int:
136
+ return self.lines_added + self.lines_removed
137
+
138
+ def to_dict(self) -> dict:
139
+ return {
140
+ "path": self.path,
141
+ "diff": self.diff,
142
+ "lines_added": self.lines_added,
143
+ "lines_removed": self.lines_removed,
144
+ # original/proposed stored for review display — not for rollback (snapshot used)
145
+ "original": self.original,
146
+ "proposed": self.proposed,
147
+ }
148
+
149
+
150
+ # ── Patch ──────────────────────────────────────────────────────────────────────
151
+
152
+
153
+ @dataclass
154
+ class Patch:
155
+ """
156
+ A proposed code change from a fix agent.
157
+ Immutable after creation — never modify in place.
158
+ """
159
+
160
+ # Identity
161
+ id: str = field(default_factory=lambda: str(uuid.uuid4())[:8])
162
+ agent: str = "" # fix agent that produced this
163
+ patch_type: PatchType = PatchType.BUG_FIX
164
+ finding_id: str = "" # the finding this fixes (from scanner)
165
+
166
+ # Content
167
+ changes: list[FileChange] = field(default_factory=list)
168
+ description: str = "" # human-readable summary
169
+ ai_explanation: str = "" # why this fix is correct
170
+
171
+ # Scoring
172
+ risk_score: int = 0 # 0–100
173
+ confidence: int = 100 # 0–100
174
+ blast_radius: int = 0 # total files affected by changing target files
175
+
176
+ # State
177
+ state: PatchState = PatchState.PROPOSED
178
+ snapshot_id: str = "" # snapshot taken before applying
179
+
180
+ # Timestamps
181
+ proposed_at: str = field(default_factory=_now)
182
+ applied_at: str = ""
183
+ rejected_at: str = ""
184
+ rolled_back_at: str = ""
185
+
186
+ # Test results (populated after apply)
187
+ test_result: dict = field(default_factory=dict)
188
+
189
+ # Detect-fix-verify loop (MISS-15)
190
+ scanner_agent: str = "" # scanner agent that found the original issue
191
+ source_finding: dict = field(default_factory=dict) # original finding dict
192
+ verify_retries: int = 0 # number of retries remaining (max 2)
193
+
194
+ # Test-weakening guard: a fix that only edits test files must go to
195
+ # human review, never auto-apply (set by the verify loop / risk gate).
196
+ requires_review: bool = False
197
+
198
+ # Metadata
199
+ extra: dict = field(default_factory=dict)
200
+
201
+ @property
202
+ def file_count(self) -> int:
203
+ return len(self.changes)
204
+
205
+ @property
206
+ def total_lines_changed(self) -> int:
207
+ return sum(c.lines_changed for c in self.changes)
208
+
209
+ @property
210
+ def affected_paths(self) -> list[str]:
211
+ return [c.path for c in self.changes]
212
+
213
+ @property
214
+ def risk_level(self) -> str:
215
+ from patchi.core.constants import RiskLevel
216
+
217
+ return RiskLevel.from_score(self.risk_score).value
218
+
219
+ def to_dict(self) -> dict:
220
+ return {
221
+ "id": self.id,
222
+ "agent": self.agent,
223
+ "patch_type": self.patch_type.value,
224
+ "finding_id": self.finding_id,
225
+ "changes": [c.to_dict() for c in self.changes],
226
+ "description": self.description,
227
+ "ai_explanation": self.ai_explanation,
228
+ "risk_score": self.risk_score,
229
+ "risk_level": self.risk_level,
230
+ "confidence": self.confidence,
231
+ "blast_radius": self.blast_radius,
232
+ "state": self.state.value,
233
+ "snapshot_id": self.snapshot_id,
234
+ "proposed_at": self.proposed_at,
235
+ "applied_at": self.applied_at,
236
+ "rejected_at": self.rejected_at,
237
+ "rolled_back_at": self.rolled_back_at,
238
+ "test_result": self.test_result,
239
+ "scanner_agent": self.scanner_agent,
240
+ "source_finding": self.source_finding,
241
+ "verify_retries": self.verify_retries,
242
+ "requires_review": self.requires_review,
243
+ "file_count": self.file_count,
244
+ "total_lines": self.total_lines_changed,
245
+ "affected_paths": self.affected_paths,
246
+ }
247
+
248
+ @staticmethod
249
+ def from_dict(d: dict) -> Patch:
250
+ changes = [
251
+ FileChange(
252
+ path=c["path"],
253
+ original=c.get("original", ""),
254
+ proposed=c.get("proposed", ""),
255
+ diff=c.get("diff", ""),
256
+ )
257
+ for c in d.get("changes", [])
258
+ ]
259
+ p = Patch(
260
+ id=d.get("id", str(uuid.uuid4())[:8]),
261
+ agent=d.get("agent", ""),
262
+ patch_type=PatchType(d.get("patch_type", "bug_fix")),
263
+ finding_id=d.get("finding_id", ""),
264
+ changes=changes,
265
+ description=d.get("description", ""),
266
+ ai_explanation=d.get("ai_explanation", ""),
267
+ risk_score=d.get("risk_score", 0),
268
+ confidence=d.get("confidence", 100),
269
+ blast_radius=d.get("blast_radius", 0),
270
+ state=PatchState(d.get("state", "proposed")),
271
+ snapshot_id=d.get("snapshot_id", ""),
272
+ proposed_at=d.get("proposed_at", _now()),
273
+ applied_at=d.get("applied_at", ""),
274
+ rejected_at=d.get("rejected_at", ""),
275
+ rolled_back_at=d.get("rolled_back_at", ""),
276
+ test_result=d.get("test_result", {}),
277
+ scanner_agent=d.get("scanner_agent", ""),
278
+ source_finding=d.get("source_finding", {}),
279
+ verify_retries=d.get("verify_retries", 0),
280
+ requires_review=d.get("requires_review", False),
281
+ )
282
+ return p
283
+
284
+
285
+ # ── Risk scorer ────────────────────────────────────────────────────────────────
286
+
287
+ # Patterns that indicate high-risk areas
288
+ _HIGH_RISK_PATHS = [
289
+ "auth",
290
+ "login",
291
+ "oauth",
292
+ "session",
293
+ "token",
294
+ "password",
295
+ "payment",
296
+ "stripe",
297
+ "checkout",
298
+ "billing",
299
+ "invoice",
300
+ "migration",
301
+ "schema",
302
+ "database",
303
+ "db",
304
+ "admin",
305
+ "permission",
306
+ "role",
307
+ "secret",
308
+ "credential",
309
+ ]
310
+
311
+ _HIGH_RISK_PATTERN = _re.compile("|".join(_HIGH_RISK_PATHS), _re.IGNORECASE)
312
+
313
+
314
+ def compute_risk_score(
315
+ changes: list[FileChange],
316
+ blast_radius: int = 0,
317
+ extra_signals: dict | None = None,
318
+ ) -> int:
319
+ """
320
+ Compute risk score (0–100) for a set of file changes.
321
+ Higher = more dangerous.
322
+ """
323
+ score = 0
324
+ extra = extra_signals or {}
325
+
326
+ # Multi-file penalty
327
+ if len(changes) > 1:
328
+ score += min((len(changes) - 1) * 10, 30)
329
+
330
+ # Lines changed
331
+ total_lines = sum(c.lines_changed for c in changes)
332
+ score += min((total_lines // 20) * 5, 30)
333
+
334
+ # High-risk path detection
335
+ for change in changes:
336
+ if _HIGH_RISK_PATTERN.search(change.path):
337
+ score += 25
338
+ break # only penalise once even if multiple high-risk files
339
+
340
+ # Database / schema changes
341
+ if any("migration" in c.path.lower() or "schema" in c.path.lower() for c in changes):
342
+ score += 20
343
+
344
+ # Error handling changes
345
+ import re
346
+
347
+ error_pattern = re.compile(r"(try:|except|catch\s*\(|finally:|\.catch\()")
348
+ for change in changes:
349
+ diff_lines = change.diff.splitlines()
350
+ modified = [
351
+ line[1:]
352
+ for line in diff_lines
353
+ if line.startswith(("+", "-")) and not line.startswith(("+++", "---"))
354
+ ]
355
+ if any(error_pattern.search(line) for line in modified):
356
+ score += 15
357
+ break
358
+
359
+ # Function signature changes
360
+ sig_pattern = re.compile(r"^[+-]\s*(def |function |async def |async function )")
361
+ for change in changes:
362
+ sig_changes = [line for line in change.diff.splitlines() if sig_pattern.match(line)]
363
+ score += min(len(sig_changes) * 8, 24)
364
+
365
+ # Blast radius
366
+ if blast_radius > 10:
367
+ score += 10
368
+ elif blast_radius > 2:
369
+ score += 5
370
+
371
+ # Agent-provided signals
372
+ if extra.get("touches_contract"):
373
+ score += 20
374
+ if extra.get("no_test_coverage"):
375
+ score += 10
376
+
377
+ return min(100, max(0, score))
378
+
379
+
380
+ def compute_confidence(
381
+ changes: list[FileChange],
382
+ agent_certainty: float = 1.0,
383
+ has_parse_errors: bool = False,
384
+ has_test_coverage: bool = True,
385
+ multiple_interpretations: bool = False,
386
+ ) -> int:
387
+ """
388
+ Compute confidence score (0–100). Higher = more certain this fix is correct.
389
+ """
390
+ score = 100
391
+
392
+ score -= int((1.0 - agent_certainty) * 20)
393
+
394
+ if has_parse_errors:
395
+ score -= 15
396
+
397
+ if not has_test_coverage:
398
+ score -= 20
399
+
400
+ if multiple_interpretations:
401
+ score -= 5
402
+
403
+ return min(100, max(0, score))
404
+
405
+
406
+ # ── Standalone helpers (used by auto_fixer and red_team_engine) ────────────────
407
+
408
+
409
+ def list_patches(root: Path) -> list[dict]:
410
+ """List all patches in .patchi/patches/."""
411
+ patches_dir = root / ".patchi" / "patches"
412
+ if not patches_dir.is_dir():
413
+ return []
414
+ results = []
415
+ for p in patches_dir.glob("*.json"):
416
+ try:
417
+ data = json.loads(p.read_text(encoding="utf-8"))
418
+ results.append(data)
419
+ except Exception:
420
+ continue
421
+ return results
422
+
423
+
424
+ def save_patch(root: Path, patch: Patch) -> Path:
425
+ """Save a patch to .patchi/patches/."""
426
+ patches_dir = root / ".patchi" / "patches"
427
+ patches_dir.mkdir(parents=True, exist_ok=True)
428
+ path = patches_dir / f"{patch.id}.json"
429
+ path.write_text(json.dumps(patch.to_dict(), indent=2), encoding="utf-8")
430
+ return path
431
+
432
+
433
+ def save_patch_state(root: Path, patch_id: str, state: PatchState) -> None:
434
+ """Update the state of a saved patch."""
435
+ path = root / ".patchi" / "patches" / f"{patch_id}.json"
436
+ if path.is_file():
437
+ try:
438
+ data = json.loads(path.read_text(encoding="utf-8"))
439
+ data["state"] = state.value
440
+ path.write_text(json.dumps(data, indent=2), encoding="utf-8")
441
+ except Exception as _exc:
442
+ _log.warning('save_patch_state failed: %s', _exc)
443
+
444
+