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
File without changes
@@ -0,0 +1,417 @@
1
+ """
2
+ EmailAuthenticationAgent — email authentication and header security.
3
+
4
+ Detects email-related security issues:
5
+ - Missing or misconfigured SPF records
6
+ - Missing or misconfigured DKIM records
7
+ - Missing or misconfigured DMARC records
8
+ - CRLF injection in email headers
9
+ - Hardcoded SMTP credentials
10
+ - Insecure email sending patterns (smtplib without TLS)
11
+ - Missing rate limiting on email endpoints
12
+
13
+ Uses static file analysis and optional external tools (dig, checkdmarc).
14
+ Does NOT call AI.
15
+ Does NOT write to disk.
16
+ Does NOT touch the queue.
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import logging
22
+ import re
23
+ import shutil
24
+ import subprocess
25
+ from pathlib import Path
26
+
27
+ from ..agents.base import (
28
+ AgentDomain,
29
+ AgentGroup,
30
+ AgentInput,
31
+ AgentResult,
32
+ AgentStatus,
33
+ BaseAgent,
34
+ Finding,
35
+ Severity,
36
+ make_finding,
37
+ register,
38
+ safe_rglob,
39
+ )
40
+ from ..brain.trace_log import trace_agent
41
+
42
+ _SOURCE_EXTENSIONS = {
43
+ "*.py",
44
+ "*.js",
45
+ "*.jsx",
46
+ "*.ts",
47
+ "*.tsx",
48
+ "*.java",
49
+ "*.php",
50
+ "*.rb",
51
+ "*.go",
52
+ "*.rs",
53
+ "*.cs",
54
+ }
55
+
56
+ _SMTP_PATTERNS = [
57
+ (re.compile(r"\bsmtplib\b|smtplib\.SMTP|smtplib\.SMTP_SSL"), "Python smtplib"),
58
+ (re.compile(r"\bsendgrid\b|SendGrid|send_grid"), "SendGrid SDK"),
59
+ (re.compile(r"\bSES\b|aws[-_]?ses|boto.*ses"), "AWS SES"),
60
+ (re.compile(r"\bMailgun\b|mailgun"), "Mailgun"),
61
+ (re.compile(r"\bpostmark\b|Postmark"), "Postmark"),
62
+ (re.compile(r"\bnodemailer\b|createTransport"), "Nodemailer"),
63
+ (re.compile(r"\bphpmailer\b|PHPMailer"), "PHPMailer"),
64
+ (re.compile(r"\bswiftmailer\b|SwiftMailer|Swift_Message"), "SwiftMailer"),
65
+ (re.compile(r"\bmail\s*\(|mb_send_mail|wp_mail"), "PHP mail()"),
66
+ (re.compile(r"\bSMTP\b.*\bconnect\b|\bsmtp_client\b", re.IGNORECASE), "Generic SMTP client"),
67
+ ]
68
+
69
+ _SMTP_CREDENTIAL_PATTERNS = [
70
+ (
71
+ re.compile(
72
+ r"(?:smtp[_-]?(?:password|pass|pwd|secret|key|token))\s*[:=]\s*['\"][^'\"]{4,}['\"]",
73
+ re.IGNORECASE,
74
+ ),
75
+ "EMAILAUTH-06: Hardcoded SMTP Password",
76
+ ),
77
+ (
78
+ re.compile(
79
+ r"(?:smtp[_-]?(?:user|username|login))\s*[:=]\s*['\"][^'\"]{2,}['\"]", re.IGNORECASE
80
+ ),
81
+ "EMAILAUTH-07: Hardcoded SMTP Username",
82
+ ),
83
+ (
84
+ re.compile(
85
+ r"(?:SMTP_PASSWORD|SMTP_USER|EMAIL_PASSWORD|EMAIL_USER|MAIL_PASSWORD)\s*[:=]\s*['\"][^'\"]{4,}['\"]",
86
+ re.IGNORECASE,
87
+ ),
88
+ "EMAILAUTH-06: Hardcoded SMTP Credential Constant",
89
+ ),
90
+ (
91
+ re.compile(r"['\"](?:smtps?://[^'\"]*:[^'\"]*@)['\"]", re.IGNORECASE),
92
+ "EMAILAUTH-06: SMTP Credential in URL",
93
+ ),
94
+ ]
95
+
96
+ _CRLF_INJECTION_PATTERNS = [
97
+ (
98
+ re.compile(
99
+ r"(?:subject|to|from|cc|bcc|reply[-_]?to)\s*[=:]\s*.*\+.*\\r\\n|\\r\\n", re.IGNORECASE
100
+ ),
101
+ "EMAILAUTH-08: CRLF Injection in Email Header",
102
+ ),
103
+ (
104
+ re.compile(r"headers?\s*\[.*\]\s*=.*\+|headers?.*update.*\{", re.IGNORECASE),
105
+ "EMAILAUTH-08: Dynamic Email Header Construction",
106
+ ),
107
+ ]
108
+
109
+ _TLS_PATTERNS = [
110
+ re.compile(r"\.starttls\(\)|\.ehlo\(\)", re.IGNORECASE),
111
+ re.compile(r"SMTP_SSL|smtps://", re.IGNORECASE),
112
+ re.compile(r"context\s*=\s*ssl\.create_default_context", re.IGNORECASE),
113
+ ]
114
+
115
+
116
+ _log = logging.getLogger("patchi.security.email_authentication_agent")
117
+
118
+
119
+ @register
120
+ class EmailAuthenticationAgent(BaseAgent):
121
+ """Agent for detecting email authentication and header security issues."""
122
+
123
+ group = AgentGroup.SECURITY
124
+ domain = AgentDomain.SECURITY
125
+ name = "EmailAuthenticationAgent"
126
+ description = "Email authentication: SPF, DKIM, DMARC, header injection"
127
+
128
+ def _run(self, inp: AgentInput, result: AgentResult) -> None:
129
+ findings: list[Finding] = []
130
+ files_scanned = 0
131
+
132
+ with trace_agent(self.name, inp.root) as trace:
133
+ # ── Static analysis ────────────────────────────────────────────
134
+ findings.extend(self._scan_spf_dkim_dmarc(inp))
135
+ findings.extend(self._scan_smtp_code(inp))
136
+ findings.extend(self._scan_crlf_injection(inp))
137
+ findings.extend(self._scan_tls_usage(inp))
138
+
139
+ for pattern in _SOURCE_EXTENSIONS:
140
+ for fp in safe_rglob(inp.root, pattern):
141
+ if fp.is_file():
142
+ files_scanned += 1
143
+ findings.extend(self._scan_file(fp, inp.root))
144
+
145
+ # ── External tools ─────────────────────────────────────────────
146
+ if shutil.which("dig"):
147
+ findings.extend(self._run_dig_email_checks(inp))
148
+
149
+ trace.findings = len(findings)
150
+ trace.files_scanned = files_scanned
151
+
152
+ result.status = AgentStatus.SUCCEEDED
153
+ result.findings = findings
154
+ result.data.update(
155
+ {
156
+ "email_auth_findings": len(findings),
157
+ "dig_available": shutil.which("dig") is not None,
158
+ }
159
+ )
160
+ return
161
+
162
+ # ── SPF/DKIM/DMARC config scan ────────────────────────────────────────
163
+
164
+ def _scan_spf_dkim_dmarc(self, inp: AgentInput) -> list[Finding]:
165
+ findings: list[Finding] = []
166
+ for pattern in ("*.tf", "*.yaml", "*.yml", "*.json", "*.conf", "*.dns", "*.zone"):
167
+ for fp in safe_rglob(inp.root, pattern):
168
+ if not fp.is_file():
169
+ continue
170
+ rel = fp.relative_to(inp.root).as_posix()
171
+ try:
172
+ content = fp.read_text(encoding="utf-8", errors="replace")
173
+ content_lower = content.lower()
174
+ if any(k in content_lower for k in ("dns", "zone", "domain", "mx", "mail")):
175
+ if "spf" not in content_lower and "txt" not in content_lower:
176
+ findings.append(
177
+ make_finding(
178
+ severity=Severity.HIGH,
179
+ file=rel,
180
+ line_start=0,
181
+ title="EMAILAUTH-01: No SPF Record Found",
182
+ description="DNS/mail configuration without SPF record. Emails may be spoofed.",
183
+ suggestion="Add an SPF TXT record (e.g., v=spf1 include:_spf.google.com ~all).",
184
+ )
185
+ )
186
+ if "dkim" not in content_lower:
187
+ findings.append(
188
+ make_finding(
189
+ severity=Severity.HIGH,
190
+ file=rel,
191
+ line_start=0,
192
+ title="EMAILAUTH-02: No DKIM Record Found",
193
+ description="DNS/mail configuration without DKIM. Email integrity cannot be verified.",
194
+ suggestion="Configure DKIM signing and publish the public key as a DNS TXT record.",
195
+ )
196
+ )
197
+ if "dmarc" not in content_lower:
198
+ findings.append(
199
+ make_finding(
200
+ severity=Severity.HIGH,
201
+ file=rel,
202
+ line_start=0,
203
+ title="EMAILAUTH-03: No DMARC Record Found",
204
+ description="No DMARC policy found. Spoofed emails will not be rejected.",
205
+ suggestion="Add a DMARC TXT record (e.g., v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com).",
206
+ )
207
+ )
208
+ except Exception as e:
209
+ _log.warning("EmailAuthenticationAgent._scan_spf_dkim_dmarc failed: %s", e)
210
+ return findings
211
+
212
+ # ── SMTP code patterns ─────────────────────────────────────────────────
213
+
214
+ def _scan_smtp_code(self, inp: AgentInput) -> list[Finding]:
215
+ findings: list[Finding] = []
216
+ for pattern in ("*.py", "*.js", "*.ts", "*.php", "*.rb", "*.go", "*.java"):
217
+ for fp in safe_rglob(inp.root, pattern):
218
+ if not fp.is_file():
219
+ continue
220
+ rel = fp.relative_to(inp.root).as_posix()
221
+ try:
222
+ content = fp.read_text(encoding="utf-8", errors="replace")
223
+ lines = content.splitlines()
224
+ for i, line in enumerate(lines, 1):
225
+ for rx, desc in _SMTP_PATTERNS:
226
+ if rx.search(line):
227
+ findings.append(
228
+ make_finding(
229
+ severity=Severity.LOW,
230
+ file=rel,
231
+ line_start=i,
232
+ title="EMAILAUTH-04: Email Sending Code Detected",
233
+ description=f"Email sending code found: {desc}. Verify authentication is properly configured.",
234
+ evidence=line.strip()[:120],
235
+ )
236
+ )
237
+ break
238
+ except Exception as e:
239
+ _log.warning("EmailAuthenticationAgent._scan_smtp_code failed: %s", e)
240
+ return findings
241
+
242
+ # ── CRLF injection ─────────────────────────────────────────────────────
243
+
244
+ def _scan_crlf_injection(self, inp: AgentInput) -> list[Finding]:
245
+ findings: list[Finding] = []
246
+ for pattern in ("*.py", "*.js", "*.ts", "*.php", "*.rb", "*.go", "*.java"):
247
+ for fp in safe_rglob(inp.root, pattern):
248
+ if not fp.is_file():
249
+ continue
250
+ rel = fp.relative_to(inp.root).as_posix()
251
+ try:
252
+ content = fp.read_text(encoding="utf-8", errors="replace")
253
+ lines = content.splitlines()
254
+ for i, line in enumerate(lines, 1):
255
+ for rx, desc in _CRLF_INJECTION_PATTERNS:
256
+ if rx.search(line):
257
+ findings.append(
258
+ make_finding(
259
+ severity=Severity.HIGH,
260
+ file=rel,
261
+ line_start=i,
262
+ title=desc,
263
+ description="User-controlled input may be injected into email headers via CRLF.",
264
+ evidence=line.strip()[:120],
265
+ suggestion="Sanitize header values: strip \\r\\n characters before use.",
266
+ )
267
+ )
268
+ except Exception as e:
269
+ _log.warning("EmailAuthenticationAgent._scan_crlf_injection failed: %s", e)
270
+ return findings
271
+
272
+ # ── TLS usage in SMTP ──────────────────────────────────────────────────
273
+
274
+ def _scan_tls_usage(self, inp: AgentInput) -> list[Finding]:
275
+ findings: list[Finding] = []
276
+ for pattern in ("*.py", "*.js", "*.ts", "*.php", "*.rb"):
277
+ for fp in safe_rglob(inp.root, pattern):
278
+ if not fp.is_file():
279
+ continue
280
+ rel = fp.relative_to(inp.root).as_posix()
281
+ try:
282
+ content = fp.read_text(encoding="utf-8", errors="replace")
283
+ # _SMTP_PATTERNS entries are (regex, label) tuples.
284
+ has_smtp = any(rx.search(content) for rx, _ in _SMTP_PATTERNS[:3])
285
+ if has_smtp:
286
+ has_tls = any(rx.search(content) for rx in _TLS_PATTERNS)
287
+ if not has_tls:
288
+ lines = content.splitlines()
289
+ for i, line in enumerate(lines, 1):
290
+ if any(rx.search(line) for rx, _ in _SMTP_PATTERNS[:3]):
291
+ findings.append(
292
+ make_finding(
293
+ severity=Severity.HIGH,
294
+ file=rel,
295
+ line_start=i,
296
+ title="EMAILAUTH-05: SMTP Without TLS",
297
+ description="SMTP connection found without TLS/STARTTLS. Credentials and content sent in cleartext.",
298
+ evidence=line.strip()[:120],
299
+ suggestion="Use SMTP_SSL or call starttls() before sending.",
300
+ )
301
+ )
302
+ break
303
+ except Exception as e:
304
+ _log.warning("EmailAuthenticationAgent._scan_tls_usage failed: %s", e)
305
+ return findings
306
+
307
+ # ── General source file scan (credentials) ─────────────────────────────
308
+
309
+ def _scan_file(self, fp: Path, root: Path) -> list[Finding]:
310
+ findings: list[Finding] = []
311
+ rel = fp.relative_to(root).as_posix()
312
+ try:
313
+ content = fp.read_text(encoding="utf-8", errors="replace")
314
+ lines = content.splitlines()
315
+ for i, line in enumerate(lines, 1):
316
+ for rx, title in _SMTP_CREDENTIAL_PATTERNS:
317
+ if rx.search(line):
318
+ findings.append(
319
+ make_finding(
320
+ severity=Severity.CRITICAL,
321
+ file=rel,
322
+ line_start=i,
323
+ title=title,
324
+ description="Hardcoded SMTP credential found in source code.",
325
+ evidence=line.strip()[:120],
326
+ suggestion="Move SMTP credentials to environment variables or a secrets manager.",
327
+ )
328
+ )
329
+ except Exception as e:
330
+ _log.warning("EmailAuthenticationAgent._scan_file failed: %s", e)
331
+ return findings
332
+
333
+ # ── External tool: dig ─────────────────────────────────────────────────
334
+
335
+ def _run_dig_email_checks(self, inp: AgentInput) -> list[Finding]:
336
+ """Run dig to check SPF/DKIM/DMARC DNS records."""
337
+ findings: list[Finding] = []
338
+ domain = inp.config.get("email_check_domain")
339
+ if not domain or not isinstance(domain, str):
340
+ return findings
341
+
342
+ # Check SPF
343
+ try:
344
+ proc = subprocess.run(
345
+ ["dig", "+short", "txt", domain, "+timeout=5"],
346
+ capture_output=True,
347
+ text=True,
348
+ timeout=10,
349
+ )
350
+ if proc.returncode == 0:
351
+ output = proc.stdout.lower()
352
+ if "v=spf1" not in output:
353
+ findings.append(
354
+ make_finding(
355
+ severity=Severity.HIGH,
356
+ file="(dns_probe)",
357
+ line_start=0,
358
+ title="EMAILAUTH-01: No SPF Record",
359
+ description=f"No SPF record found for {domain}.",
360
+ evidence=proc.stdout[:200],
361
+ suggestion="Add an SPF TXT record.",
362
+ )
363
+ )
364
+ except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
365
+ pass
366
+
367
+ # Check DKIM (common selector)
368
+ for selector in ("default", "google", "selector1", "selector2", "k1"):
369
+ try:
370
+ proc = subprocess.run(
371
+ ["dig", "+short", "txt", f"{selector}._domainkey.{domain}", "+timeout=5"],
372
+ capture_output=True,
373
+ text=True,
374
+ timeout=10,
375
+ )
376
+ if proc.returncode == 0 and proc.stdout.strip():
377
+ break # Found DKIM record
378
+ except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
379
+ pass
380
+ else:
381
+ findings.append(
382
+ make_finding(
383
+ severity=Severity.HIGH,
384
+ file="(dns_probe)",
385
+ line_start=0,
386
+ title="EMAILAUTH-02: No DKIM Record Found",
387
+ description=f"No DKIM record found for {domain} (checked common selectors).",
388
+ suggestion="Configure DKIM and publish the public key.",
389
+ )
390
+ )
391
+
392
+ # Check DMARC
393
+ try:
394
+ proc = subprocess.run(
395
+ ["dig", "+short", "txt", f"_dmarc.{domain}", "+timeout=5"],
396
+ capture_output=True,
397
+ text=True,
398
+ timeout=10,
399
+ )
400
+ if proc.returncode == 0:
401
+ output = proc.stdout.lower()
402
+ if "v=dmarc1" not in output:
403
+ findings.append(
404
+ make_finding(
405
+ severity=Severity.HIGH,
406
+ file="(dns_probe)",
407
+ line_start=0,
408
+ title="EMAILAUTH-03: No DMARC Record",
409
+ description=f"No DMARC record found for {domain}.",
410
+ evidence=proc.stdout[:200],
411
+ suggestion="Add a DMARC TXT record with at minimum p=none for monitoring.",
412
+ )
413
+ )
414
+ except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
415
+ pass
416
+
417
+ return findings