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,295 @@
1
+ """Cloud WAF Detector — AWS WAF & Cloudflare WAF misconfiguration and bypass detection.
2
+
3
+ Scans project infrastructure code for WAF misconfigurations:
4
+ - Missing WAF on public-facing ALB/CloudFront/API Gateway
5
+ - Rate limits too permissive or absent
6
+ - Missing OWASP core rule set or managed rules
7
+ - Geo-blocking not configured for admin endpoints
8
+ - Cloudflare: missing bot management, browser integrity check, or rate limiting
9
+ - Cloudflare: wide-open page rules, disabled security in page rules
10
+ - AWS WAF: missing IP set restrictions on admin paths
11
+
12
+ Also detects WAF bypass attempts in intercepted requests:
13
+ - HTTP parameter pollution
14
+ - Encoding bypasses (double URL encoding, unicode, comments)
15
+ - HTTP method tunneling
16
+ - Case manipulation
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import logging
22
+ import re
23
+
24
+ from ..agents.base import (
25
+ AgentGroup,
26
+ AgentInput,
27
+ AgentResult,
28
+ AgentStatus,
29
+ BaseAgent,
30
+ Finding,
31
+ Severity,
32
+ register,
33
+ safe_rglob,
34
+ )
35
+
36
+ _log = logging.getLogger("patchi.security.cloud_waf_detector")
37
+
38
+
39
+ @register
40
+ class CloudWAFDetector(BaseAgent):
41
+ """Detect AWS WAF & Cloudflare WAF misconfigurations and bypass patterns."""
42
+
43
+ group = AgentGroup.SECURITY
44
+ name = "CloudWAFDetector"
45
+ description = "Cloud WAF misconfiguration and bypass detection"
46
+
47
+ # ── Cloudflare page rule patterns that disable security ──
48
+ CF_INSECURE_PAGE_RULES = re.compile(
49
+ r"(security\s*=\s*\"off\"|disable_security|security_level\s*=\s*\"essentially_off\")",
50
+ re.IGNORECASE,
51
+ )
52
+ CF_WIDE_OPEN_CACHE = re.compile(
53
+ r"(edge_cache_ttl\s*=\s*0|cache_level\s*=\s*\"bypass\")",
54
+ re.IGNORECASE,
55
+ )
56
+
57
+ # ── Terraform AWS WAF patterns (positive match = issue) ──
58
+ MISSING_WAF_PATTERNS: list[tuple[str, str, str, Severity]] = [
59
+ (
60
+ "aws_alb",
61
+ r"resource\s+\"aws_alb\"",
62
+ "ALB without WAF association — add aws_wafv2_web_acl_association",
63
+ Severity.HIGH,
64
+ ),
65
+ (
66
+ "aws_lb",
67
+ r"resource\s+\"aws_lb\"[^}]*?internal\s*=\s*false",
68
+ "Public ALB without WAF association — add aws_wafv2_web_acl_association",
69
+ Severity.HIGH,
70
+ ),
71
+ (
72
+ "aws_cloudfront_distribution",
73
+ r"resource\s+\"aws_cloudfront_distribution\"",
74
+ "CloudFront without WAF — add web_acl_id referencing WAFv2 ACL",
75
+ Severity.HIGH,
76
+ ),
77
+ (
78
+ "aws_api_gateway_rest_api",
79
+ r"resource\s+\"aws_api_gateway_rest_api\"",
80
+ "API Gateway without WAF — add WAFv2 ACL association",
81
+ Severity.MEDIUM,
82
+ ),
83
+ ]
84
+
85
+ WAF_WEAKNESSES: list[tuple[str, str, Severity]] = [
86
+ (
87
+ "No rate limiting configured",
88
+ r"rate_based_statement|rate_limit",
89
+ Severity.MEDIUM,
90
+ ),
91
+ (
92
+ "No AWS managed rules",
93
+ r"managed_rule_group_statement|vendor_name\s*=\s*\"aws\"",
94
+ Severity.MEDIUM,
95
+ ),
96
+ (
97
+ "No OWASP CRS",
98
+ r"core_rule_set|owasp.*crs|managed_rule.*owasp",
99
+ Severity.MEDIUM,
100
+ ),
101
+ ]
102
+
103
+ WAF_MISCONFIG_PATTERNS: list[tuple[str, str, str, Severity]] = [
104
+ (
105
+ "allow_all_default",
106
+ r"default_action\s*\{\s*allow\s*\}",
107
+ "WAF default action is ALLOW — should be BLOCK with explicit allow rules",
108
+ Severity.HIGH,
109
+ ),
110
+ (
111
+ "no_ip_restriction_admin",
112
+ r"geo_match_statement|ip_set_reference_statement",
113
+ "No Geo/IP restriction on admin paths detected",
114
+ Severity.MEDIUM,
115
+ ),
116
+ ]
117
+
118
+ # ── Bypass patterns in request data ──
119
+ WAF_BYPASS_PATTERNS: list[tuple[str, str, Severity]] = [
120
+ (
121
+ "HTTP parameter pollution",
122
+ r"(&|\?)[^=]+=[^&]*&[^=]+=[^&]*(&[^=]+=[^&]*)+",
123
+ Severity.MEDIUM,
124
+ ),
125
+ (
126
+ "Double URL encoding",
127
+ r"%25[0-9a-fA-F]{2}",
128
+ Severity.MEDIUM,
129
+ ),
130
+ (
131
+ "Unicode encoding bypass",
132
+ r"\\u[0-9a-fA-F]{4}|%u[0-9a-fA-F]{4}",
133
+ Severity.LOW,
134
+ ),
135
+ (
136
+ "HTTP method tunneling",
137
+ r"(X-HTTP-Method-Override|X-HTTP-Method|X-Method-Override):\s*\w+",
138
+ Severity.MEDIUM,
139
+ ),
140
+ (
141
+ "Case manipulation bypass",
142
+ r"(<[Ss][Cc][Rr][Ii][Pp][Tt]>|<[Ss][Vv][Gg]/[Oo][Nn][Ll][Oo][Aa][Dd])",
143
+ Severity.LOW,
144
+ ),
145
+ ]
146
+
147
+ def _run(self, inp: AgentInput, result: AgentResult) -> None:
148
+ root = inp.root
149
+ findings: list[Finding] = []
150
+
151
+ # Phase 1: Scan IaC files for WAF misconfigs
152
+ # safe_rglob yields generators — materialize before concatenating.
153
+ tf_files = list(safe_rglob(root, "*.tf"))
154
+ cf_files = list(safe_rglob(root, "*.yaml")) + list(safe_rglob(root, "*.yml"))
155
+ ia_files = tf_files + [
156
+ f for f in cf_files if "cloudflare" in str(f).lower() or "waf" in str(f).lower()
157
+ ]
158
+
159
+ for fp in ia_files:
160
+ try:
161
+ text = fp.read_text(encoding="utf-8", errors="replace")
162
+ except Exception as e:
163
+ _log.warning("CloudWAFDetector._run failed: %s", e)
164
+ continue
165
+ rel = str(fp.relative_to(root))
166
+
167
+ for res_name, pattern, msg, severity in self.MISSING_WAF_PATTERNS:
168
+ if re.search(pattern, text, re.IGNORECASE):
169
+ findings.append(
170
+ Finding(
171
+ agent=self.name,
172
+ type="missing_waf",
173
+ severity=severity,
174
+ file=rel,
175
+ message=f"{msg} ({res_name})",
176
+ cwe="CWE-693",
177
+ )
178
+ )
179
+
180
+ for name, pattern, severity in self.WAF_WEAKNESSES:
181
+ if not re.search(pattern, text, re.IGNORECASE):
182
+ findings.append(
183
+ Finding(
184
+ agent=self.name,
185
+ type="waf_weakness",
186
+ severity=severity,
187
+ file=rel,
188
+ message=f"WAF weakness: {name}",
189
+ cwe="CWE-693",
190
+ )
191
+ )
192
+
193
+ for name, pattern, msg, severity in self.WAF_MISCONFIG_PATTERNS:
194
+ for m in re.finditer(pattern, text, re.IGNORECASE):
195
+ findings.append(
196
+ Finding(
197
+ agent=self.name,
198
+ type="waf_" + name,
199
+ severity=severity,
200
+ file=rel,
201
+ message=msg,
202
+ snippet=m.group()[:80],
203
+ cwe="CWE-693",
204
+ )
205
+ )
206
+
207
+ # Cloudflare-specific checks
208
+ if fp.suffix == ".yaml":
209
+ m = self.CF_INSECURE_PAGE_RULES.search(text)
210
+ if m:
211
+ findings.append(
212
+ Finding(
213
+ agent=self.name,
214
+ type="cf_insecure_page_rule",
215
+ severity=Severity.HIGH,
216
+ file=rel,
217
+ message="Cloudflare page rule disables security",
218
+ snippet=m.group(),
219
+ cwe="CWE-693",
220
+ )
221
+ )
222
+
223
+ m = self.CF_WIDE_OPEN_CACHE.search(text)
224
+ if m:
225
+ findings.append(
226
+ Finding(
227
+ agent=self.name,
228
+ type="cf_bypass_cache",
229
+ severity=Severity.MEDIUM,
230
+ file=rel,
231
+ message="Cloudflare cache bypassed in page rule",
232
+ snippet=m.group(),
233
+ cwe="CWE-693",
234
+ )
235
+ )
236
+
237
+ # Phase 2: WAF bypass patterns in test/request files
238
+ test_files = list(safe_rglob(root, "*test*")) + list(safe_rglob(root, "*spec*"))
239
+ seen_bypass: set[tuple[str, str]] = set()
240
+ for fp in test_files:
241
+ if fp.suffix not in {".py", ".js", ".ts", ".http", ".txt", ".csv", ".json"}:
242
+ continue
243
+ try:
244
+ text = fp.read_text(encoding="utf-8", errors="replace")
245
+ except Exception as e:
246
+ _log.warning("CloudWAFDetector._run failed: %s", e)
247
+ continue
248
+ rel = str(fp.relative_to(root))
249
+ for name, pattern, severity in self.WAF_BYPASS_PATTERNS:
250
+ for m in re.finditer(pattern, text, re.IGNORECASE):
251
+ key = (rel, name)
252
+ if key in seen_bypass:
253
+ continue
254
+ seen_bypass.add(key)
255
+ findings.append(
256
+ Finding(
257
+ agent=self.name,
258
+ type="waf_bypass",
259
+ severity=severity,
260
+ file=rel,
261
+ message=f"WAF bypass pattern: {name}",
262
+ line=1 + text[: m.start()].count("\n"),
263
+ snippet=m.group()[:80],
264
+ cwe="CWE-693",
265
+ )
266
+ )
267
+
268
+ # Phase 3: CloudFront without origin access identity
269
+ seen_no_oai = False
270
+ for fp in tf_files:
271
+ try:
272
+ text = fp.read_text(encoding="utf-8", errors="replace")
273
+ except Exception as e:
274
+ _log.warning("CloudWAFDetector._run failed: %s", e)
275
+ continue
276
+ rel = str(fp.relative_to(root))
277
+ if re.search(r"resource\s+\"aws_cloudfront_distribution\"", text) and not re.search(
278
+ r"origin_access_identity|oai", text
279
+ ):
280
+ if not seen_no_oai:
281
+ seen_no_oai = True
282
+ findings.append(
283
+ Finding(
284
+ agent=self.name,
285
+ type="cloudfront_no_oai",
286
+ severity=Severity.MEDIUM,
287
+ file=rel,
288
+ message="CloudFront distribution without origin access identity",
289
+ cwe="CWE-693",
290
+ )
291
+ )
292
+
293
+ result.findings = findings
294
+ result.status = AgentStatus.DONE
295
+ result.files_scanned = len(ia_files) + len(test_files)
@@ -0,0 +1,233 @@
1
+ """
2
+ CodeQLAgent - CodeQL static analysis integration.
3
+
4
+ CodeQL is a semantic code analysis engine from GitHub that can find
5
+ vulnerabilities and code quality issues.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import logging
11
+ import subprocess
12
+ import tempfile
13
+ from pathlib import Path
14
+ from typing import Any
15
+
16
+ from patchi.core.agents.base import (
17
+ AgentDomain,
18
+ AgentGroup,
19
+ AgentInput,
20
+ AgentResult,
21
+ AgentStatus,
22
+ BaseAgent,
23
+ register,
24
+ )
25
+
26
+ _log = logging.getLogger("patchi.security.agents.codeql_agent")
27
+
28
+
29
+ @register
30
+ class CodeqlAgent(BaseAgent):
31
+ """
32
+ CodeQLAgent - CodeQL static analysis integration.
33
+
34
+ CodeQL is a semantic code analysis engine from GitHub that can find
35
+ vulnerabilities and code quality issues using a query-based approach.
36
+ """
37
+
38
+ group = AgentGroup.SECURITY
39
+ domain = AgentDomain.SECURITY
40
+ name = "CodeqlAgent"
41
+ description = "CodeQL semantic analysis for vulnerabilities"
42
+ # Database build + QL compilation is genuinely slow (minutes even on tiny
43
+ # projects the first time). The old 180s timeout guaranteed silent zeros.
44
+ timeout = 3600
45
+
46
+ def _run(self, inp: AgentInput, result: AgentResult) -> None:
47
+ """Run CodeQL analysis on the project."""
48
+ if not self._is_codeql_available():
49
+ result.status = AgentStatus.SKIPPED
50
+ result.data["error"] = "CodeQL CLI not installed"
51
+ return
52
+
53
+ findings = self._run_codeql(inp.root)
54
+
55
+ for finding_data in findings:
56
+ finding = self._create_finding(finding_data)
57
+ result.add_finding(finding)
58
+
59
+ result.status = AgentStatus.DONE
60
+ result.files_scanned = 1
61
+
62
+ def _is_codeql_available(self) -> bool:
63
+ """Check if CodeQL CLI is installed and available."""
64
+ try:
65
+ result = subprocess.run(["codeql", "version"], capture_output=True, timeout=10)
66
+ return result.returncode == 0
67
+ except FileNotFoundError:
68
+ return False
69
+
70
+ def _resolve_query_suite(self) -> str:
71
+ """Prefer a locally cached query pack; never hit the network.
72
+
73
+ ``--download``/bare pack names trip a CLI pack-manifest bug
74
+ (UnrecognizedPropertyException on Docker digest) and need network.
75
+ The standard install caches packs under ~/.codeql/packages.
76
+ """
77
+ candidates = sorted(
78
+ (Path.home() / ".codeql" / "packages" / "codeql" / "python-queries").glob(
79
+ "*/codeql-suites/python-security-extended.qls"
80
+ )
81
+ )
82
+ if candidates:
83
+ return str(candidates[-1])
84
+ return "python-security-extended"
85
+
86
+ def _run_codeql(self, root: Path) -> list[dict[str, Any]]:
87
+ """Create a database, run the security suite, return parsed findings."""
88
+ findings: list[dict[str, Any]] = []
89
+ suite = self._resolve_query_suite()
90
+
91
+ with tempfile.TemporaryDirectory() as tmpdir:
92
+ db_dir = Path(tmpdir) / "codeql_db"
93
+ results_file = Path(tmpdir) / "results.sarif"
94
+
95
+ try:
96
+ # ── Phase 1: database create ────────────────────────────────
97
+ result = subprocess.run(
98
+ [
99
+ "codeql",
100
+ "database",
101
+ "create",
102
+ str(db_dir),
103
+ "--language=python",
104
+ "--source-root",
105
+ str(root),
106
+ ],
107
+ capture_output=True,
108
+ text=True,
109
+ encoding="utf-8",
110
+ errors="replace",
111
+ timeout=900,
112
+ cwd=str(root),
113
+ )
114
+
115
+ if result.returncode != 0:
116
+ tail = (result.stderr or result.stdout or "")[-300:]
117
+ _log.warning("CodeQL database creation failed: %s", tail)
118
+ return findings
119
+
120
+ # ── Phase 2: analyze against the security suite ─────────────
121
+ result = subprocess.run(
122
+ [
123
+ "codeql",
124
+ "database",
125
+ "analyze",
126
+ str(db_dir),
127
+ suite,
128
+ "--format=sarif-latest",
129
+ "--output",
130
+ str(results_file),
131
+ "--sarif-add-snippets",
132
+ ],
133
+ capture_output=True,
134
+ text=True,
135
+ encoding="utf-8",
136
+ errors="replace",
137
+ timeout=3600,
138
+ cwd=str(root),
139
+ )
140
+
141
+ if result.returncode != 0:
142
+ tail = (result.stderr or result.stdout or "")[-300:]
143
+ _log.warning("CodeQL analyze failed: %s", tail)
144
+ return findings
145
+
146
+ if results_file.exists():
147
+ with open(results_file, encoding="utf-8") as f:
148
+ data = json.load(f)
149
+ return self._parse_sarif_output(data)
150
+
151
+ except subprocess.TimeoutExpired:
152
+ _log.warning("CodeQL timed out")
153
+ except Exception as e: # noqa: BLE001 — tool failures are data
154
+ _log.warning("CodeQL execution failed: %s", e)
155
+
156
+ return findings
157
+
158
+ def _parse_sarif_output(self, data: dict[str, Any]) -> list[dict[str, Any]]:
159
+ """Parse SARIF into finding dicts with full fidelity.
160
+
161
+ Extracts per-rule metadata (CWE tags, numeric security-severity)
162
+ and per-result code snippets so downstream scoring and AI review
163
+ get real context instead of bare rule ids.
164
+ """
165
+ findings: list[dict[str, Any]] = []
166
+
167
+ for run in data.get("runs", []):
168
+ # Rule metadata lives in tool.driver.rules / extensions
169
+ rules_by_id: dict[str, dict[str, Any]] = {}
170
+ for tool in run.get("tool", {}).get("driver", {}).get("rules", []) + [
171
+ r for ext in run.get("tool", {}).get("extensions", []) for r in ext.get("rules", [])
172
+ ]:
173
+ rid = tool.get("id", "")
174
+ if rid:
175
+ rules_by_id[rid] = tool
176
+
177
+ for result in run.get("results", []):
178
+ rule_id = result.get("ruleId", "codeql_finding")
179
+ rule_meta = rules_by_id.get(rule_id, {})
180
+ props = rule_meta.get("properties", {}) or {}
181
+
182
+ # Severity: prefer numeric security-severity (0-10)
183
+ sec_sev = props.get("security-severity")
184
+ level = result.get("level") or props.get("problem.severity") or "warning"
185
+
186
+ # CWE from tags like "security/cwe/cwe-089"
187
+ cwe = ""
188
+ for tag in props.get("tags", []) or []:
189
+ tag_l = str(tag).lower()
190
+ if "cwe-" in tag_l:
191
+ idx = tag_l.index("cwe-")
192
+ num = "".join(ch for ch in tag_l[idx + 4 :] if ch.isdigit())
193
+ if num:
194
+ cwe = f"CWE-{int(num)}"
195
+ break
196
+
197
+ location = result.get("locations", [{}])[0].get("physicalLocation", {})
198
+ artifact = location.get("artifactLocation", {})
199
+ region = location.get("region", {})
200
+ snippet = (region.get("snippet", {}) or {}).get("text", "")
201
+
202
+ findings.append(
203
+ {
204
+ "type": rule_id,
205
+ "severity": sec_sev if sec_sev is not None else level,
206
+ "file": artifact.get("uri", ""),
207
+ "line": region.get("startLine", 0),
208
+ "message": (result.get("message", {}) or {}).get("text", ""),
209
+ "cwe": cwe,
210
+ "snippet": snippet,
211
+ "rule_id": rule_id,
212
+ }
213
+ )
214
+ return findings
215
+
216
+ def _create_finding(self, finding_data: dict[str, Any]):
217
+ """Create a Finding object from CodeQL output."""
218
+ from patchi.core.security.tool_adapters import make_tool_finding
219
+
220
+ return make_tool_finding(
221
+ agent="CodeqlAgent",
222
+ ftype=finding_data.get("type", "codeql_finding"),
223
+ raw_severity=finding_data.get("severity", "MEDIUM"),
224
+ file=finding_data.get("file", ""),
225
+ line=finding_data.get("line", 0),
226
+ message=finding_data.get("message", ""),
227
+ cwe=finding_data.get("cwe", ""),
228
+ snippet=finding_data.get("snippet", ""),
229
+ confidence_raw=0.8, # database-query findings: semantic, not pattern
230
+ extra={"rule_id": finding_data.get("rule_id", "")},
231
+ )
232
+
233
+