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,110 @@
1
+ """Self-Improvement dashboard — agent profiles, learning, threat model."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import logging
7
+ from pathlib import Path
8
+
9
+ from fastapi import APIRouter, Request
10
+ from fastapi.responses import HTMLResponse, JSONResponse
11
+ from fastapi.templating import Jinja2Templates
12
+
13
+ _log = logging.getLogger("patchi.web.routes.self_improvement")
14
+
15
+
16
+ router = APIRouter()
17
+ templates = Jinja2Templates(directory=str(Path(__file__).parent.parent / "templates"))
18
+
19
+
20
+ def _load_json(root: Path, rel: str) -> dict:
21
+ p = root / rel
22
+ if p.is_file():
23
+ try:
24
+ return json.loads(p.read_text(encoding="utf-8"))
25
+ except Exception as _exc:
26
+ _log.warning('_load_json failed: %s', _exc)
27
+ return {}
28
+
29
+
30
+ @router.get("/self-improvement", response_class=HTMLResponse)
31
+ async def self_improvement(request: Request):
32
+ root = request.app.state.root
33
+
34
+ # Agent profiles
35
+ try:
36
+ from patchi.core.ai.agent_profiler import get_all_profiles, get_profile_summary
37
+
38
+ profile_summary = get_profile_summary(root)
39
+ all_profiles = get_all_profiles(root)
40
+ profiles_data = {k: v.to_dict() for k, v in all_profiles.items()}
41
+ except Exception:
42
+ profile_summary = {"agents": 0, "total_runs": 0, "total_cost": 0}
43
+ profiles_data = {}
44
+
45
+ # Learning summary
46
+ try:
47
+ from patchi.core.security.attack_feedback import get_learning_summary
48
+
49
+ learning = get_learning_summary(root)
50
+ except Exception:
51
+ learning = {"acceptances": {}, "rejections": {}, "agent_trust": {}, "skip_types": []}
52
+
53
+ # Threat model
54
+ threat_model = _load_json(root, ".patchi/threat_model.json")
55
+
56
+ # Fuzz corpus stats
57
+ try:
58
+ from patchi.core.fuzz.corpus import FuzzCorpus
59
+
60
+ corpus = FuzzCorpus(root)
61
+ corpus_stats = corpus.stats()
62
+ except Exception:
63
+ corpus_stats = {"total": 0, "avg_score": 0, "strategies": {}}
64
+
65
+ # Ignore learner stats
66
+ try:
67
+ from patchi.core.security.ignore_learner import IgnoreLearner
68
+
69
+ learner = IgnoreLearner(root)
70
+ learner.build()
71
+ ignore_count = len(learner.entries)
72
+ except Exception:
73
+ ignore_count = 0
74
+
75
+ return templates.TemplateResponse(
76
+ request,
77
+ "self_improvement.html",
78
+ {
79
+ "request": request,
80
+ "profile_summary": profile_summary,
81
+ "profiles": profiles_data,
82
+ "learning": learning,
83
+ "threat_model": threat_model,
84
+ "corpus_stats": corpus_stats,
85
+ "ignore_count": ignore_count,
86
+ },
87
+ )
88
+
89
+
90
+ @router.get("/api/self-improvement")
91
+ async def api_self_improvement(request: Request):
92
+ root = request.app.state.root
93
+ try:
94
+ from patchi.core.ai.agent_profiler import get_all_profiles, get_profile_summary
95
+ from patchi.core.security.attack_feedback import get_learning_summary
96
+
97
+ profile_summary = get_profile_summary(root)
98
+ all_profiles = get_all_profiles(root)
99
+ learning = get_learning_summary(root)
100
+ threat_model = _load_json(root, ".patchi/threat_model.json")
101
+ return JSONResponse(
102
+ {
103
+ "profiles": profile_summary,
104
+ "agent_details": {k: v.to_dict() for k, v in all_profiles.items()},
105
+ "learning": learning,
106
+ "threat_model": threat_model,
107
+ }
108
+ )
109
+ except Exception as e:
110
+ return JSONResponse({"error": str(e)}, status_code=500)
@@ -0,0 +1,49 @@
1
+ """Settings route — web UI configuration panel."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ from fastapi import APIRouter, Request
8
+ from fastapi.responses import HTMLResponse
9
+ from fastapi.templating import Jinja2Templates
10
+
11
+ router = APIRouter()
12
+ templates = Jinja2Templates(directory=str(Path(__file__).parent.parent / "templates"))
13
+
14
+
15
+ @router.get("/settings", response_class=HTMLResponse)
16
+ async def settings_page(request: Request):
17
+ root = request.app.state.root
18
+ from patchi.core import config as cfg
19
+ from patchi.core import memory as mem
20
+
21
+ brain = mem.get_brain(root)
22
+ config = cfg.load(root)
23
+
24
+ safe_keys = {
25
+ "mode",
26
+ "theme",
27
+ "device_tier",
28
+ "scan_depth",
29
+ "risk_threshold",
30
+ "queue_mode",
31
+ "quiet_hours_start",
32
+ "quiet_hours_end",
33
+ "max_parallel_agents",
34
+ "max_queue_depth",
35
+ "websocket_timeout",
36
+ }
37
+ safe_config = {k: v for k, v in config.items() if k in safe_keys}
38
+
39
+ return templates.TemplateResponse(
40
+ request,
41
+ "settings.html",
42
+ {
43
+ "request": request,
44
+ "config": safe_config,
45
+ "framework": brain.get("framework", "Unknown"),
46
+ "health_score": brain.get("health_score", {}).get("total", 0),
47
+ "ai_keys": len(config.get("ai", {}).get("keys", [])),
48
+ },
49
+ )
@@ -0,0 +1,29 @@
1
+ """Tokens route — admin token management page."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ from fastapi import APIRouter, Request
8
+ from fastapi.responses import HTMLResponse
9
+ from fastapi.templating import Jinja2Templates
10
+
11
+ router = APIRouter()
12
+ templates = Jinja2Templates(directory=str(Path(__file__).parent.parent / "templates"))
13
+
14
+
15
+ @router.get("/tokens", response_class=HTMLResponse)
16
+ async def tokens_page(request: Request):
17
+ root = request.app.state.root
18
+ from patchi.core.hosted import tokens as tokens_mod
19
+
20
+ token_list = tokens_mod.list_tokens(root)
21
+
22
+ return templates.TemplateResponse(
23
+ request,
24
+ "tokens.html",
25
+ {
26
+ "request": request,
27
+ "tokens": token_list,
28
+ },
29
+ )
patchi/web/spawn.py ADDED
@@ -0,0 +1,139 @@
1
+ """
2
+ Tap-to-spawn handler for the Patchi Brain Map.
3
+
4
+ Enforces the full spec from patchi_builder_sidenote.md:
5
+ - Max 5 user-spawned ants simultaneously
6
+ - 10-second tap cooldown per node
7
+ - 60-second ant expiry
8
+ - No spawn if Patchi is idle (returns None — caller shows node inspector)
9
+ - No spawn on restricted nodes
10
+ - No spawn if 3+ ants already working on the node
11
+ - Second tap on same node within 10s is ignored
12
+
13
+ SpawnManager is instantiated once on server start and shared via FastAPI state.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import time
19
+ import uuid
20
+ from dataclasses import dataclass, field
21
+ from pathlib import Path
22
+
23
+ import patchi.core.config as config
24
+
25
+ # Spec constants
26
+ MAX_USER_ANTS = 5
27
+ NODE_COOLDOWN_S = 10
28
+ ANT_EXPIRY_S = 60
29
+ MAX_ANTS_ON_NODE = 3
30
+
31
+
32
+ @dataclass
33
+ class SpawnedAnt:
34
+ ant_id: str
35
+ node_id: str
36
+ spawned_at: float = field(default_factory=time.time)
37
+ done: bool = False
38
+
39
+ def is_expired(self) -> bool:
40
+ return (time.time() - self.spawned_at) > ANT_EXPIRY_S
41
+
42
+
43
+ class SpawnManager:
44
+ """
45
+ Tracks all user-spawned ants. Called by the WebSocket handler when
46
+ the client sends an `action.spawn_ant` event.
47
+ """
48
+
49
+ def __init__(self, root: Path) -> None:
50
+ self._root = root
51
+ self._ants: dict[str, SpawnedAnt] = {} # ant_id → SpawnedAnt
52
+ self._taps: dict[str, float] = {} # node_id → last tap timestamp
53
+ self._is_active: bool = False # set by server when a scan runs
54
+
55
+ # ── Lifecycle ─────────────────────────────────────────────────────────────
56
+
57
+ def set_active(self, active: bool) -> None:
58
+ """Called by the scan runner to indicate whether Patchi is running."""
59
+ self._is_active = active
60
+
61
+ def mark_done(self, ant_id: str) -> None:
62
+ if ant_id in self._ants:
63
+ self._ants[ant_id].done = True
64
+
65
+ # ── Spawn gate ────────────────────────────────────────────────────────────
66
+
67
+ def try_spawn(self, node_id: str) -> tuple[str | None, str]:
68
+ """
69
+ Attempt to spawn an ant on node_id.
70
+
71
+ Returns (ant_id, reason):
72
+ - (ant_id, "ok") → spawned successfully
73
+ - (None, "idle") → Patchi not running — show inspector instead
74
+ - (None, "restricted") → node is restricted
75
+ - (None, "cooldown") → same node tapped within 10s
76
+ - (None, "capacity") → 5 user-spawned ants already active
77
+ - (None, "node_busy") → 3+ ants already on this node
78
+ """
79
+ self._expire_ants()
80
+
81
+ if not self._is_active:
82
+ return None, "idle"
83
+
84
+ if self._is_restricted(node_id):
85
+ return None, "restricted"
86
+
87
+ if self._on_cooldown(node_id):
88
+ return None, "cooldown"
89
+
90
+ live = self._live_ants()
91
+ if len(live) >= MAX_USER_ANTS:
92
+ return None, "capacity"
93
+
94
+ ants_on_node = sum(1 for a in live.values() if a.node_id == node_id)
95
+ if ants_on_node >= MAX_ANTS_ON_NODE:
96
+ return None, "node_busy"
97
+
98
+ ant_id = str(uuid.uuid4())[:8]
99
+ self._ants[ant_id] = SpawnedAnt(ant_id=ant_id, node_id=node_id)
100
+ self._taps[node_id] = time.time()
101
+ return ant_id, "ok"
102
+
103
+ def active_count(self) -> int:
104
+ self._expire_ants()
105
+ return len(self._live_ants())
106
+
107
+ def all_active(self) -> list[dict]:
108
+ self._expire_ants()
109
+ return [
110
+ {"ant_id": a.ant_id, "node_id": a.node_id, "age_s": int(time.time() - a.spawned_at)}
111
+ for a in self._live_ants().values()
112
+ ]
113
+
114
+ # ── Internal helpers ──────────────────────────────────────────────────────
115
+
116
+ def _live_ants(self) -> dict[str, SpawnedAnt]:
117
+ return {aid: a for aid, a in self._ants.items() if not a.done and not a.is_expired()}
118
+
119
+ def _expire_ants(self) -> None:
120
+ expired = [aid for aid, ant in self._ants.items() if ant.is_expired()]
121
+ for aid in expired:
122
+ del self._ants[aid]
123
+
124
+ def _on_cooldown(self, node_id: str) -> bool:
125
+ last = self._taps.get(node_id, 0.0)
126
+ return (time.time() - last) < NODE_COOLDOWN_S
127
+
128
+ def _is_restricted(self, node_id: str) -> bool:
129
+ """Check config restrictions. node_id is the file path used as Brain Map node key."""
130
+ try:
131
+ restrictions = config.get_restrictions(self._root)
132
+ return any(r["path"] == node_id and r.get("enabled", True) for r in restrictions)
133
+ except Exception as e:
134
+ import logging
135
+
136
+ logging.getLogger("patchi.web.spawn").warning(
137
+ "Restriction check failed for %s: %s", node_id, e
138
+ )
139
+ return False
patchi/web/ws.py ADDED
@@ -0,0 +1,141 @@
1
+ """
2
+ WebSocket manager for live events.
3
+
4
+ Broadcasts scan progress, finding alerts, guard events to all connected clients.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import asyncio
10
+ import json
11
+ import time
12
+ from dataclasses import dataclass, field
13
+ from typing import Any
14
+
15
+
16
+ @dataclass
17
+ class WSManager:
18
+ """Manages WebSocket connections and broadcasts events."""
19
+
20
+ _connections: list = field(default_factory=list)
21
+ _lock: asyncio.Lock = field(default_factory=asyncio.Lock)
22
+
23
+ async def connect(self, ws: Any) -> None:
24
+ async with self._lock:
25
+ self._connections.append(ws)
26
+
27
+ async def disconnect(self, ws: Any) -> None:
28
+ async with self._lock:
29
+ if ws in self._connections:
30
+ self._connections.remove(ws)
31
+
32
+ async def broadcast(self, event: str, data: dict | None = None) -> None:
33
+ """Send event to all connected clients."""
34
+ message = json.dumps(
35
+ {
36
+ "event": event,
37
+ "data": data or {},
38
+ "ts": time.time(),
39
+ }
40
+ )
41
+ async with self._lock:
42
+ targets = list(self._connections)
43
+ dead = []
44
+ for ws in targets:
45
+ try:
46
+ await ws.send_text(message)
47
+ except Exception:
48
+ dead.append(ws)
49
+ for ws in dead:
50
+ if ws in self._connections:
51
+ self._connections.remove(ws)
52
+ if dead:
53
+ import logging
54
+
55
+ logging.getLogger("patchi.web.ws").warning(
56
+ "Removed %d dead WS connection(s)", len(dead)
57
+ )
58
+
59
+ @property
60
+ def connection_count(self) -> int:
61
+ return len(self._connections)
62
+
63
+
64
+ # Global instance
65
+ manager = WSManager()
66
+
67
+
68
+ # ── Event helpers ─────────────────────────────────────────────────────────────
69
+
70
+
71
+ async def evt_scan_started(agent_count: int = 0) -> None:
72
+ await manager.broadcast("scan.started", {"agent_count": agent_count})
73
+
74
+
75
+ async def evt_scan_progress(agent: str, phase: str, current: int, total: int) -> None:
76
+ await manager.broadcast(
77
+ "scan.progress",
78
+ {
79
+ "agent": agent,
80
+ "phase": phase,
81
+ "current": current,
82
+ "total": total,
83
+ },
84
+ )
85
+
86
+
87
+ async def evt_scan_finding(finding: dict) -> None:
88
+ await manager.broadcast("scan.finding", finding)
89
+
90
+
91
+ async def evt_scan_complete(total_findings: int, duration_ms: int) -> None:
92
+ await manager.broadcast(
93
+ "scan.complete",
94
+ {
95
+ "total_findings": total_findings,
96
+ "duration_ms": duration_ms,
97
+ },
98
+ )
99
+
100
+
101
+ async def evt_scan_cancelled(total_findings: int) -> None:
102
+ await manager.broadcast(
103
+ "scan.cancelled",
104
+ {"total_findings": total_findings},
105
+ )
106
+
107
+
108
+ async def evt_agent_started(agent_name: str) -> None:
109
+ await manager.broadcast("agent.started", {"agent": agent_name})
110
+
111
+
112
+ async def evt_agent_done(agent_name: str, finding_count: int) -> None:
113
+ await manager.broadcast(
114
+ "agent.done",
115
+ {
116
+ "agent": agent_name,
117
+ "finding_count": finding_count,
118
+ },
119
+ )
120
+
121
+
122
+ async def evt_guard_alert(alert: dict) -> None:
123
+ await manager.broadcast("guard.alert", alert)
124
+
125
+
126
+ async def evt_guard_status(status: dict) -> None:
127
+ await manager.broadcast("guard.status", status)
128
+
129
+
130
+ async def evt_fix_applied(patch_id: str, file_path: str) -> None:
131
+ await manager.broadcast(
132
+ "fix.applied",
133
+ {
134
+ "patch_id": patch_id,
135
+ "file_path": file_path,
136
+ },
137
+ )
138
+
139
+
140
+ async def evt_status_update(status: dict) -> None:
141
+ await manager.broadcast("status.update", status)