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,104 @@
1
+ """
2
+ CrossRepo §11.3 — multi-repo index for shared library drift.
3
+
4
+ Indexes multiple repo roots (siblings or explicit list) and compares dependency versions + API usage.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import logging
11
+ import re
12
+ from pathlib import Path
13
+
14
+ _log = logging.getLogger("patchi.brain.cross_repo")
15
+
16
+ def index_repos(roots: list[Path]) -> dict:
17
+ idx={}
18
+ for r in roots:
19
+ try:
20
+ from patchi.core.brain.file_corpus import FileCorpus
21
+ corpus=FileCorpus(r)
22
+ idx[str(r)]={"files": len(list(corpus.files())), "deps": _deps(r)}
23
+ except Exception:
24
+ idx[str(r)]={"files":0,"deps":{}}
25
+ return idx
26
+
27
+ def _deps(root: Path) -> dict:
28
+ """Parsed {package: version} per manifest (not raw text)."""
29
+ deps: dict[str, dict[str, str]] = {}
30
+ try:
31
+ p = root / "package.json"
32
+ if p.exists():
33
+ pkg = json.loads(p.read_text(encoding="utf-8", errors="replace"))
34
+ merged = {}
35
+ for section in ("dependencies", "devDependencies", "peerDependencies"):
36
+ for name, ver in (pkg.get(section) or {}).items():
37
+ merged[str(name)] = str(ver)
38
+ if merged:
39
+ deps["package.json"] = merged
40
+ except Exception as _exc:
41
+ _log.debug("package.json parse failed: %s", _exc)
42
+ try:
43
+ p = root / "requirements.txt"
44
+ if p.exists():
45
+ parsed = {}
46
+ for line in p.read_text(encoding="utf-8", errors="replace").splitlines():
47
+ line = line.strip()
48
+ if not line or line.startswith(("#", "-", " ")):
49
+ continue
50
+ m = re.match(r"^([A-Za-z0-9_.\-]+)\s*(?:==|>=|<=|~=|!=|>|<)?\s*([^;\s]*)", line)
51
+ if m:
52
+ parsed[m.group(1).lower()] = m.group(2) or "unpinned"
53
+ if parsed:
54
+ deps["requirements.txt"] = parsed
55
+ except Exception as _exc:
56
+ _log.debug("requirements parse failed: %s", _exc)
57
+ try:
58
+ p = root / "go.mod"
59
+ if p.exists():
60
+ parsed = {}
61
+ for line in p.read_text(encoding="utf-8", errors="replace").splitlines():
62
+ m = re.match(r"^\s*([a-z0-9./\-_]+)\s+(v[\w.+\-]+)", line.strip(), re.I)
63
+ if m and "module" not in line and "go " != line[:3]:
64
+ parsed[m.group(1)] = m.group(2)
65
+ if parsed:
66
+ deps["go.mod"] = parsed
67
+ except Exception as _exc:
68
+ _log.debug("go.mod parse failed: %s", _exc)
69
+ try:
70
+ p = root / "Cargo.toml"
71
+ if p.exists():
72
+ parsed = {}
73
+ in_deps = False
74
+ for line in p.read_text(encoding="utf-8", errors="replace").splitlines():
75
+ s = line.strip()
76
+ if s.startswith("["):
77
+ in_deps = "dependencies" in s
78
+ continue
79
+ if in_deps:
80
+ m = re.match(r"^([A-Za-z0-9_\-]+)\s*=\s*\"?([^\"]*)\"?", s)
81
+ if m:
82
+ parsed[m.group(1)] = m.group(2) or "unpinned"
83
+ if parsed:
84
+ deps["Cargo.toml"] = parsed
85
+ except Exception as _exc:
86
+ _log.debug("Cargo.toml parse failed: %s", _exc)
87
+ return deps
88
+
89
+ def drift_report(roots: list[Path]) -> dict:
90
+ idx=index_repos(roots)
91
+ # real version drift: same package, different versions across repos
92
+ seen: dict[str, dict[str, list]] = {}
93
+ for r, data in idx.items():
94
+ for pkgs in data.get("deps", {}).values():
95
+ if not isinstance(pkgs, dict):
96
+ continue
97
+ for name, ver in pkgs.items():
98
+ seen.setdefault(name, {}).setdefault(str(ver), []).append(r)
99
+ drift=[]
100
+ for name, versions in seen.items():
101
+ if len(versions) > 1:
102
+ drift.append({"package": name[:80],
103
+ "versions": {v: rs[:3] for v, rs in versions.items()}})
104
+ return {"index": idx, "drift": drift[:10]}
@@ -0,0 +1,157 @@
1
+ """
2
+ External tool runners for symbol-level dead code detection.
3
+
4
+ Each runner invokes a language-specific tool and normalizes its output
5
+ into a list of dicts with keys: symbol, file, line, tool, confidence.
6
+
7
+ Tools:
8
+ - vulture (Python) — already a dependency
9
+ - ts-prune (JS/TS) — npm package, optional
10
+ - deadcode (Python) — alternative to vulture
11
+ - ruff (Python) — unused imports via F401
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import shutil
18
+ import subprocess
19
+ from pathlib import Path
20
+ from typing import TYPE_CHECKING
21
+
22
+ if TYPE_CHECKING:
23
+ from patchi.core.brain.file_corpus import FileCorpus
24
+
25
+
26
+ def run_vulture(root: Path, min_confidence: int = 60) -> list[dict]:
27
+ """Run vulture on a Python project and return unused symbols."""
28
+ if not shutil.which("vulture"):
29
+ return []
30
+ try:
31
+ proc = subprocess.run(
32
+ ["vulture", str(root), "--min-confidence", str(min_confidence), "--json"],
33
+ capture_output=True,
34
+ text=True,
35
+ timeout=30,
36
+ )
37
+ if proc.returncode not in (0, 1):
38
+ return []
39
+ results = []
40
+ for line in proc.stdout.splitlines():
41
+ line = line.strip()
42
+ if not line:
43
+ continue
44
+ try:
45
+ entry = json.loads(line)
46
+ results.append(
47
+ {
48
+ "symbol": entry.get("name", ""),
49
+ "file": entry.get("filename", ""),
50
+ "line": entry.get("lineno", 0),
51
+ "tool": "vulture",
52
+ "confidence": entry.get("confidence", min_confidence),
53
+ }
54
+ )
55
+ except json.JSONDecodeError:
56
+ continue
57
+ return results
58
+ except (subprocess.TimeoutExpired, Exception):
59
+ return []
60
+
61
+
62
+ def run_ruff_unused_imports(root: Path) -> list[dict]:
63
+ """Run ruff to find unused imports (F401) across the project."""
64
+ if not shutil.which("ruff"):
65
+ return []
66
+ try:
67
+ proc = subprocess.run(
68
+ ["ruff", "check", str(root), "--select=F401", "--output-format=json"],
69
+ capture_output=True,
70
+ text=True,
71
+ timeout=30,
72
+ )
73
+ results = []
74
+ for line in proc.stdout.splitlines():
75
+ line = line.strip()
76
+ if not line:
77
+ continue
78
+ try:
79
+ entry = json.loads(line)
80
+ if entry.get("code") == "F401":
81
+ results.append(
82
+ {
83
+ "symbol": entry.get("message", "").split("'")[1]
84
+ if "'" in entry.get("message", "")
85
+ else "",
86
+ "file": entry.get("filename", ""),
87
+ "line": entry.get("location", {}).get("row", 0),
88
+ "tool": "ruff",
89
+ "confidence": 90,
90
+ }
91
+ )
92
+ except (json.JSONDecodeError, IndexError):
93
+ continue
94
+ return results
95
+ except (subprocess.TimeoutExpired, Exception):
96
+ return []
97
+
98
+
99
+ def run_ts_prune(root: Path) -> list[dict]:
100
+ """Run ts-prune on a TypeScript project to find unused exports."""
101
+ if not shutil.which("npx"):
102
+ return []
103
+ pkg_json = root / "package.json"
104
+ if not pkg_json.exists():
105
+ return []
106
+ try:
107
+ proc = subprocess.run(
108
+ ["npx", "--yes", "ts-prune", "--json"],
109
+ capture_output=True,
110
+ text=True,
111
+ timeout=60,
112
+ cwd=str(root),
113
+ )
114
+ results = []
115
+ for line in proc.stdout.splitlines():
116
+ line = line.strip()
117
+ if not line:
118
+ continue
119
+ try:
120
+ entry = json.loads(line)
121
+ if entry.get("isDefault", False):
122
+ continue
123
+ results.append(
124
+ {
125
+ "symbol": entry.get("symbol", ""),
126
+ "file": entry.get("file", ""),
127
+ "line": 0,
128
+ "tool": "ts-prune",
129
+ "confidence": 70,
130
+ }
131
+ )
132
+ except json.JSONDecodeError:
133
+ continue
134
+ return results
135
+ except (subprocess.TimeoutExpired, Exception):
136
+ return []
137
+
138
+
139
+ def detect_and_run(root: Path, corpus: FileCorpus | None = None) -> list[dict]:
140
+ """Auto-detect project type and run all applicable dead code tools."""
141
+ results: list[dict] = []
142
+
143
+ has_python = any(corpus.by_ext(".py")) if corpus else any(root.rglob("*.py"))
144
+ has_ts = (
145
+ any(corpus.by_ext(".ts", ".tsx"))
146
+ if corpus
147
+ else any(root.rglob("*.ts")) or any(root.rglob("*.tsx"))
148
+ )
149
+
150
+ if has_python:
151
+ results.extend(run_vulture(root))
152
+ results.extend(run_ruff_unused_imports(root))
153
+
154
+ if has_ts:
155
+ results.extend(run_ts_prune(root))
156
+
157
+ return results
@@ -0,0 +1,197 @@
1
+ """
2
+ Documentation claim validator.
3
+
4
+ Parses README and documentation files for factual claims about the project
5
+ (code features, API endpoints, supported formats, etc.), cross-references
6
+ each claim against the actual scanned code, and stores validated claims in
7
+ the brain for use by fix agents and contract inference.
8
+
9
+ This prevents the classic problem of docs saying "supports X" when X was
10
+ removed months ago.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import re
16
+ from pathlib import Path
17
+ from typing import Any
18
+
19
+ from patchi.core.brain.languages import DEFAULT_IGNORE_DIRS
20
+ from patchi.core.brain.route_mapper import RouteInfo
21
+ from patchi.core.brain.scanner import FileInfo
22
+
23
+ # ── Claim extraction ────────────────────────────────────────────────────────────
24
+
25
+ # Patterns that look like documented features in README files
26
+ _CLAIM_PATTERNS = [
27
+ re.compile(
28
+ r"(?:supports?|handles?|manages?|provides?|offers?|features?)\s+([^.,]+)", re.IGNORECASE
29
+ ),
30
+ re.compile(r"- \[x\]\s*(.+)", re.IGNORECASE), # checkbox done
31
+ re.compile(r"\*\*(.+?)\*\*\s*(?:—|–|-|:)\s*.+", re.IGNORECASE), # **Feature** — description
32
+ re.compile(
33
+ r"(?:API|endpoint|route)\s*[`:/]\s*([A-Za-z0-9_/{}]+)", re.IGNORECASE
34
+ ), # inline API mentions
35
+ re.compile(
36
+ r"(?:CLI|command)\s*[`:]\s*([a-z][a-z0-9_-]+)", re.IGNORECASE
37
+ ), # inline CLI mentions
38
+ ]
39
+
40
+
41
+ def extract_claims(doc_path: Path) -> list[str]:
42
+ """Parse a documentation file and return a list of raw claim strings."""
43
+ if not doc_path.exists():
44
+ return []
45
+ try:
46
+ text = doc_path.read_text(encoding="utf-8", errors="replace")
47
+ except OSError:
48
+ return []
49
+
50
+ claims: list[str] = []
51
+ for pattern in _CLAIM_PATTERNS:
52
+ for m in pattern.finditer(text):
53
+ claim = m.group(1).strip()
54
+ if len(claim) > 15 and claim not in claims:
55
+ claims.append(claim)
56
+ return claims
57
+
58
+
59
+ def _tokenize(text: str) -> set[str]:
60
+ """Split text into lowercase tokens for overlap matching."""
61
+ return set(re.findall(r"[a-z][a-z0-9_]{2,}", text.lower()))
62
+
63
+
64
+ def _code_vocabulary(file_infos: list[FileInfo], routes: list[RouteInfo]) -> dict[str, list[str]]:
65
+ """Build a token→evidence map from the actual codebase."""
66
+ vocab: dict[str, list[str]] = {}
67
+ for fi in file_infos:
68
+ for token in _tokenize(fi.path):
69
+ vocab.setdefault(token, []).append(f"file: {fi.path}")
70
+ for func in fi.functions:
71
+ for token in _tokenize(func.name):
72
+ vocab.setdefault(token, []).append(f"file: {fi.path} function: {func.name}")
73
+ for cls in fi.classes:
74
+ for token in _tokenize(cls.name):
75
+ vocab.setdefault(token, []).append(f"file: {fi.path} class: {cls.name}")
76
+ for route in routes:
77
+ for token in _tokenize(route.path):
78
+ vocab.setdefault(token, []).append(f"route: {route.method} {route.path}")
79
+ return vocab
80
+
81
+
82
+ def cross_reference_claim(
83
+ claim: str,
84
+ file_infos: list[FileInfo],
85
+ routes: list[RouteInfo],
86
+ ) -> tuple[bool, list[str]]:
87
+ """
88
+ Check if a claim is backed by actual code.
89
+ Uses token-overlap matching instead of hardcoded keyword lists.
90
+ Returns (verified, evidence_list).
91
+ """
92
+ claim_tokens = _tokenize(claim)
93
+ if not claim_tokens:
94
+ return False, []
95
+
96
+ vocab = _code_vocabulary(file_infos, routes)
97
+ evidence: list[str] = []
98
+ scored: dict[str, float] = {}
99
+
100
+ for token in claim_tokens:
101
+ for ev in vocab.get(token, []):
102
+ scored[ev] = scored.get(ev, 0) + 1
103
+
104
+ # Sort by overlap count, take top matches
105
+ for ev, _ in sorted(scored.items(), key=lambda x: -x[1]):
106
+ if ev not in evidence:
107
+ evidence.append(ev)
108
+ if len(evidence) >= 5:
109
+ break
110
+
111
+ verified = len(evidence) >= 1
112
+ return verified, evidence[:5]
113
+
114
+
115
+ # ── Main validation entry point ────────────────────────────────────────────────
116
+
117
+
118
+ def validate_project_docs(
119
+ root: Path,
120
+ file_infos: list[FileInfo],
121
+ routes: list[RouteInfo],
122
+ ai_config: dict | None = None,
123
+ ) -> dict[str, Any]:
124
+ """
125
+ Validate all documentation files in a project against scanned code.
126
+
127
+ Returns a dict with:
128
+ - validated_claims: list of {claim, evidence, verified}
129
+ - stale_claims: list of {claim, reason} (claims that could not be verified)
130
+ - summary: plain-English summary of doc health
131
+ """
132
+ # Find doc files (skip .venv, node_modules, __pycache__)
133
+ _EXCLUDED_DIRS = DEFAULT_IGNORE_DIRS | {"files 6", ".vscode", ".idea"}
134
+
135
+ doc_files = []
136
+ for pattern in ("README*", "*.md", "docs/**/*.md"):
137
+ if "*" in pattern:
138
+ matched = list(root.glob(pattern))
139
+ # Filter out excluded directories
140
+ matched = [
141
+ p
142
+ for p in matched
143
+ if not any(part in _EXCLUDED_DIRS for part in p.relative_to(root).parts)
144
+ ]
145
+ else:
146
+ p = root / pattern
147
+ if p.exists():
148
+ matched = [p]
149
+ else:
150
+ matched = []
151
+ doc_files.extend(matched)
152
+ doc_files = sorted(set(doc_files))
153
+
154
+ all_claims: list[tuple[str, Path]] = []
155
+ for doc_path in doc_files:
156
+ for claim in extract_claims(doc_path):
157
+ all_claims.append((claim, doc_path))
158
+
159
+ result = {
160
+ "validated_claims": [],
161
+ "stale_claims": [],
162
+ "summary": "",
163
+ "doc_files_found": [str(p) for p in doc_files],
164
+ "total_claims": 0,
165
+ }
166
+
167
+ for claim, doc_path in all_claims:
168
+ verified, evidence = cross_reference_claim(claim, file_infos, routes)
169
+ entry = {
170
+ "claim": claim,
171
+ "source": str(doc_path),
172
+ "verified": verified,
173
+ "evidence": evidence,
174
+ }
175
+ if verified:
176
+ result["validated_claims"].append(entry)
177
+ else:
178
+ result["stale_claims"].append(entry)
179
+
180
+ result["total_claims"] = len(all_claims)
181
+ result["summary"] = _build_summary(result)
182
+ return result
183
+
184
+
185
+ def _build_summary(result: dict) -> str:
186
+ total = result["total_claims"]
187
+ validated = len(result["validated_claims"])
188
+ stale = len(result["stale_claims"])
189
+ doc_count = len(result["doc_files_found"])
190
+
191
+ if total == 0:
192
+ return f"Found {doc_count} doc file(s) but no verifiable claims."
193
+
194
+ parts = [f"Verified {validated}/{total} claims across {doc_count} doc file(s)."]
195
+ if stale:
196
+ parts.append(f"{stale} claim(s) could not be verified against code")
197
+ return " ".join(parts)