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,600 @@
1
+ """
2
+ MisconfigAgent — security misconfigurations.
3
+
4
+ Detects security misconfigurations:
5
+ - Debug enabled in production
6
+ - Insecure CORS settings
7
+ - Missing security headers
8
+ - Weak TLS/SSL configurations
9
+ - Improper error handling
10
+ - Verbose error messages
11
+ - Unrestricted file uploads
12
+ - Missing rate limiting
13
+ - Default credentials
14
+ - Unnecessary services/features enabled
15
+
16
+ Uses pattern matching and configuration analysis.
17
+ Does NOT call AI.
18
+ Does NOT write to disk.
19
+ Does NOT touch the queue.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import json
25
+ from pathlib import Path
26
+
27
+ import yaml
28
+
29
+ from ..agents.base import (
30
+ AgentDomain,
31
+ AgentGroup,
32
+ AgentInput,
33
+ AgentResult,
34
+ AgentStatus,
35
+ BaseAgent,
36
+ Finding,
37
+ Severity,
38
+ make_finding,
39
+ register,
40
+ safe_rglob,
41
+ )
42
+
43
+
44
+ @register
45
+ class MisconfigAgent(BaseAgent):
46
+ """Agent for detecting security misconfigurations."""
47
+
48
+ group = AgentGroup.SECURITY
49
+ domain = AgentDomain.SECURITY
50
+ name = "MisconfigAgent"
51
+ description = (
52
+ "Security misconfig: debug, CORS, headers, TLS, error handling, file upload, rate limiting"
53
+ )
54
+
55
+ def _run(self, inp: AgentInput, result: AgentResult) -> None:
56
+ """Run security misconfiguration detection."""
57
+ findings = []
58
+
59
+ # Define configuration file patterns to scan
60
+ config_patterns = [
61
+ "*.json",
62
+ "*.yml",
63
+ "*.yaml",
64
+ "*.toml",
65
+ "*.xml",
66
+ "*.ini",
67
+ "*.cfg",
68
+ "*.conf",
69
+ ".env*",
70
+ "*rc",
71
+ ".gitignore",
72
+ ".dockerignore",
73
+ "Dockerfile*",
74
+ "package.json",
75
+ "requirements.txt",
76
+ "Cargo.toml",
77
+ "go.mod",
78
+ "composer.json",
79
+ "Gemfile",
80
+ "Pipfile",
81
+ "poetry.lock",
82
+ "yarn.lock",
83
+ "pnpm-lock.yaml",
84
+ "**/config/**",
85
+ "**/configs/**",
86
+ "**/conf/**",
87
+ "**/settings/**",
88
+ ]
89
+
90
+ # Search for configuration files
91
+ for pattern in config_patterns:
92
+ for file_path in safe_rglob(inp.root, pattern):
93
+ if file_path.is_file():
94
+ rel_path = file_path.relative_to(inp.root).as_posix()
95
+ if not self._should_skip_file(rel_path, inp):
96
+ findings.extend(self._scan_config_file_misconfig(file_path, rel_path))
97
+
98
+ # Also scan source files for misconfigurations
99
+ source_patterns = [
100
+ "*.py",
101
+ "*.js",
102
+ "*.jsx",
103
+ "*.ts",
104
+ "*.tsx",
105
+ "*.java",
106
+ "*.php",
107
+ "*.rb",
108
+ "*.go",
109
+ "*.rs",
110
+ "*.cpp",
111
+ "*.cxx",
112
+ "*.cc",
113
+ "*.c",
114
+ "*.h",
115
+ "*.hpp",
116
+ "*.cs",
117
+ ]
118
+
119
+ for pattern in source_patterns:
120
+ for file_path in safe_rglob(inp.root, pattern):
121
+ if file_path.is_file():
122
+ rel_path = file_path.relative_to(inp.root).as_posix()
123
+ if not self._should_skip_file(rel_path, inp):
124
+ findings.extend(self._scan_source_file_misconfig(file_path, rel_path))
125
+
126
+ result.status = AgentStatus.SUCCEEDED
127
+ result.findings = findings
128
+ result.data.update(
129
+ {
130
+ "misconfig_findings": len(
131
+ [
132
+ f
133
+ for f in findings
134
+ if any(
135
+ word in f.title.lower()
136
+ for word in [
137
+ "misconfig",
138
+ "debug",
139
+ "cors",
140
+ "header",
141
+ "tls",
142
+ "error",
143
+ "upload",
144
+ "rate",
145
+ ]
146
+ )
147
+ ]
148
+ ),
149
+ "needs_ai": False,
150
+ }
151
+ )
152
+ return
153
+
154
+ def _should_skip_file(self, file_path: str, inp: AgentInput) -> bool:
155
+ """Check if file should be skipped based on restrictions."""
156
+ from pathlib import PurePosixPath
157
+
158
+ # Check restrictions
159
+ restrictions = inp.config.get("restrictions", [])
160
+ for r in restrictions:
161
+ if r.get("enabled", True):
162
+ path = r["path"]
163
+ if file_path.startswith(path) or PurePosixPath(file_path).match(path):
164
+ if r["type"] == "NO_TOUCH":
165
+ return True
166
+ elif r["type"] == "SCAN_ONLY" and self.__class__.__name__ == "FixAgent":
167
+ return True
168
+ return False
169
+
170
+ def _scan_config_file_misconfig(self, file_path: Path, rel_path: str) -> list[Finding]:
171
+ """Scan a configuration file for security misconfigurations."""
172
+ findings = []
173
+
174
+ try:
175
+ content = file_path.read_text(encoding="utf-8")
176
+
177
+ # Determine file type and scan accordingly
178
+ if file_path.suffix.lower() in [".json"]:
179
+ findings.extend(self._scan_json_config_misconfig(content, rel_path))
180
+ elif file_path.suffix.lower() in [".yml", ".yaml"]:
181
+ findings.extend(self._scan_yaml_config_misconfig(content, rel_path))
182
+ elif file_path.name in ["package.json"]:
183
+ findings.extend(self._scan_package_json_misconfig(content, rel_path))
184
+ elif file_path.name in ["requirements.txt"]:
185
+ findings.extend(self._scan_requirements_txt_misconfig(content, rel_path))
186
+ elif file_path.suffix.lower() in [".toml"]:
187
+ findings.extend(self._scan_toml_config_misconfig(content, rel_path))
188
+ elif ".env" in file_path.name.lower():
189
+ findings.extend(self._scan_env_file_misconfig(content, rel_path))
190
+ else:
191
+ # General configuration file scan
192
+ findings.extend(self._scan_general_config_misconfig(content, rel_path))
193
+
194
+ except Exception as e:
195
+ findings.append(
196
+ make_finding(
197
+ severity=Severity.LOW,
198
+ file=rel_path,
199
+ line_start=0,
200
+ title="Misconfig scanner file read error",
201
+ description=f"Could not analyze {file_path.name} for misconfigurations: {str(e)}",
202
+ evidence=str(e),
203
+ )
204
+ )
205
+
206
+ return findings
207
+
208
+ def _scan_json_config_misconfig(self, content: str, rel_path: str) -> list[Finding]:
209
+ """Scan JSON configuration files for misconfigurations."""
210
+ findings = []
211
+
212
+ try:
213
+ data = json.loads(content)
214
+
215
+ # Check for debug enabled
216
+ if self._find_nested_key(data, ["debug", "DEBUG", "enable_debug", "debug_mode"]):
217
+ findings.append(
218
+ make_finding(
219
+ severity=Severity.HIGH,
220
+ file=rel_path,
221
+ line_start=0,
222
+ title="Debug Enabled in Configuration",
223
+ description="Debug mode appears to be enabled in configuration file",
224
+ evidence="Debug setting found in JSON config",
225
+ )
226
+ )
227
+
228
+ # Check for insecure settings
229
+ if self._find_nested_key(
230
+ data, ["allow_origin", "origins"], lambda v: v == "*" or v == ["*"]
231
+ ):
232
+ findings.append(
233
+ make_finding(
234
+ severity=Severity.HIGH,
235
+ file=rel_path,
236
+ line_start=0,
237
+ title="Insecure CORS Configuration",
238
+ description="CORS policy allows all origins (*)",
239
+ evidence="Wildcard CORS origin found in config",
240
+ )
241
+ )
242
+
243
+ except json.JSONDecodeError as e:
244
+ findings.append(
245
+ make_finding(
246
+ severity=Severity.LOW,
247
+ file=rel_path,
248
+ line_start=e.lineno,
249
+ title="Invalid JSON",
250
+ description=f"JSON syntax error: {str(e)}",
251
+ evidence=e.msg,
252
+ )
253
+ )
254
+
255
+ return findings
256
+
257
+ def _scan_yaml_config_misconfig(self, content: str, rel_path: str) -> list[Finding]:
258
+ """Scan YAML configuration files for misconfigurations."""
259
+ findings = []
260
+
261
+ try:
262
+ data = yaml.safe_load(content)
263
+
264
+ if isinstance(data, dict):
265
+ # Check for debug enabled
266
+ if self._find_nested_key(data, ["debug", "DEBUG", "enable_debug", "debug_mode"]):
267
+ findings.append(
268
+ make_finding(
269
+ severity=Severity.HIGH,
270
+ file=rel_path,
271
+ line_start=0,
272
+ title="Debug Enabled in Configuration",
273
+ description="Debug mode appears to be enabled in configuration file",
274
+ evidence="Debug setting found in YAML config",
275
+ )
276
+ )
277
+
278
+ # Check for insecure settings
279
+ if self._find_nested_key(
280
+ data, ["allow_origin", "origins"], lambda v: v == "*" or v == ["*"]
281
+ ):
282
+ findings.append(
283
+ make_finding(
284
+ severity=Severity.HIGH,
285
+ file=rel_path,
286
+ line_start=0,
287
+ title="Insecure CORS Configuration",
288
+ description="CORS policy allows all origins (*)",
289
+ evidence="Wildcard CORS origin found in config",
290
+ )
291
+ )
292
+
293
+ except yaml.YAMLError as e:
294
+ findings.append(
295
+ make_finding(
296
+ severity=Severity.HIGH,
297
+ file=rel_path,
298
+ line_start=0, # YAML errors don't typically include line numbers
299
+ title="Invalid YAML",
300
+ description=f"YAML syntax error: {str(e)}",
301
+ evidence=str(e),
302
+ )
303
+ )
304
+
305
+ return findings
306
+
307
+ def _scan_package_json_misconfig(self, content: str, rel_path: str) -> list[Finding]:
308
+ """Scan package.json for misconfigurations."""
309
+ findings = []
310
+
311
+ try:
312
+ data = json.loads(content)
313
+
314
+ # Check for development dependencies in production
315
+ if "devDependencies" in data and "NODE_ENV" not in content:
316
+ findings.append(
317
+ make_finding(
318
+ severity=Severity.MEDIUM,
319
+ file=rel_path,
320
+ line_start=0,
321
+ title="Potential Development Dependencies in Production",
322
+ description="package.json includes devDependencies without NODE_ENV check",
323
+ evidence="devDependencies found without environment check",
324
+ )
325
+ )
326
+
327
+ # Check for scripts that might expose vulnerabilities
328
+ scripts = data.get("scripts", {})
329
+ for script_name, script_content in scripts.items():
330
+ if any(
331
+ keyword in script_content.lower() for keyword in ["inspect", "--debug", "debug"]
332
+ ):
333
+ findings.append(
334
+ make_finding(
335
+ severity=Severity.HIGH,
336
+ file=rel_path,
337
+ line_start=0,
338
+ title="Debug Flag in Scripts",
339
+ description=f"Script '{script_name}' contains debugging flags",
340
+ evidence=script_content,
341
+ )
342
+ )
343
+
344
+ except json.JSONDecodeError as e:
345
+ findings.append(
346
+ make_finding(
347
+ severity=Severity.HIGH,
348
+ file=rel_path,
349
+ line_start=e.lineno,
350
+ title="Invalid package.json",
351
+ description=f"JSON syntax error in package.json: {str(e)}",
352
+ evidence=e.msg,
353
+ )
354
+ )
355
+
356
+ return findings
357
+
358
+ def _scan_requirements_txt_misconfig(self, content: str, rel_path: str) -> list[Finding]:
359
+ """Scan requirements.txt for misconfigurations."""
360
+ findings = []
361
+
362
+ # Check for development packages in production requirements
363
+ dev_packages = ["pytest", "mock", "faker", "factory_boy", "django-debug-toolbar"]
364
+ lines = content.splitlines()
365
+ for i, line in enumerate(lines, 1):
366
+ for pkg in dev_packages:
367
+ if pkg in line.lower():
368
+ findings.append(
369
+ make_finding(
370
+ severity=Severity.MEDIUM,
371
+ file=rel_path,
372
+ line_start=i,
373
+ title="Development Package in Requirements",
374
+ description=f"Development package '{pkg}' found in requirements.txt",
375
+ evidence=line.strip(),
376
+ )
377
+ )
378
+
379
+ return findings
380
+
381
+ def _scan_toml_config_misconfig(self, content: str, rel_path: str) -> list[Finding]:
382
+ """Scan TOML configuration files for misconfigurations."""
383
+ findings = []
384
+
385
+ # Since Python < 3.11 doesn't have built-in TOML support, we'll just do basic scanning
386
+ lines = content.splitlines()
387
+
388
+ for i, line in enumerate(lines, 1):
389
+ # Look for common misconfiguration patterns
390
+ if any(
391
+ debug_setting in line.lower()
392
+ for debug_setting in ["debug =", "debug =", "enable_debug =", "debug_mode ="]
393
+ ):
394
+ if "true" in line.lower() or "1" in line:
395
+ findings.append(
396
+ make_finding(
397
+ severity=Severity.HIGH,
398
+ file=rel_path,
399
+ line_start=i,
400
+ title="Debug Enabled in Configuration",
401
+ description="Debug mode appears to be enabled in TOML configuration",
402
+ evidence=line.strip(),
403
+ )
404
+ )
405
+
406
+ return findings
407
+
408
+ def _scan_env_file_misconfig(self, content: str, rel_path: str) -> list[Finding]:
409
+ """Scan environment files for misconfigurations."""
410
+ findings = []
411
+
412
+ lines = content.splitlines()
413
+
414
+ for i, line in enumerate(lines, 1):
415
+ # Skip comments and empty lines
416
+ if line.strip().startswith("#") or not line.strip():
417
+ continue
418
+
419
+ # Check for debug enabled
420
+ if any(
421
+ debug_var in line.upper()
422
+ for debug_var in ["DEBUG=", "FLASK_DEBUG=", "DJANGO_DEBUG="]
423
+ ):
424
+ if "TRUE" in line.upper() or "1" in line or "YES" in line.upper():
425
+ findings.append(
426
+ make_finding(
427
+ severity=Severity.HIGH,
428
+ file=rel_path,
429
+ line_start=i,
430
+ title="Debug Enabled in Environment",
431
+ description="Debug mode enabled in environment file",
432
+ evidence=line.strip(),
433
+ )
434
+ )
435
+
436
+ # Check for insecure settings
437
+ if any(
438
+ cors_var in line.upper()
439
+ for cors_var in ["CORS_ORIGIN_ALLOW_ALL=", "ALLOWED_HOSTS="]
440
+ ):
441
+ if "*" in line or '"*"' in line or "'*'" in line:
442
+ findings.append(
443
+ make_finding(
444
+ severity=Severity.HIGH,
445
+ file=rel_path,
446
+ line_start=i,
447
+ title="Insecure CORS Configuration",
448
+ description="Wildcard allowed in CORS settings",
449
+ evidence=line.strip(),
450
+ )
451
+ )
452
+
453
+ return findings
454
+
455
+ def _scan_general_config_misconfig(self, content: str, rel_path: str) -> list[Finding]:
456
+ """General configuration file scanning."""
457
+ findings = []
458
+
459
+ lines = content.splitlines()
460
+
461
+ for i, line in enumerate(lines, 1):
462
+ # Look for common misconfiguration patterns
463
+ if any(
464
+ pattern in line.lower()
465
+ for pattern in ["debug=true", "debug: true", "enable_debug=1", "debug_mode=yes"]
466
+ ):
467
+ findings.append(
468
+ make_finding(
469
+ severity=Severity.HIGH,
470
+ file=rel_path,
471
+ line_start=i,
472
+ title="Debug Enabled in Configuration",
473
+ description="Debug mode appears to be enabled in configuration",
474
+ evidence=line.strip(),
475
+ )
476
+ )
477
+
478
+ # Check for insecure CORS
479
+ if any(
480
+ cors_pattern in line.lower()
481
+ for cors_pattern in ["*.*", "allowed_origins=*", "origin_allow_all=true"]
482
+ ):
483
+ findings.append(
484
+ make_finding(
485
+ severity=Severity.HIGH,
486
+ file=rel_path,
487
+ line_start=i,
488
+ title="Insecure CORS Configuration",
489
+ description="Insecure CORS configuration detected",
490
+ evidence=line.strip(),
491
+ )
492
+ )
493
+
494
+ return findings
495
+
496
+ def _scan_source_file_misconfig(self, file_path: Path, rel_path: str) -> list[Finding]:
497
+ """Scan source files for misconfigurations."""
498
+ findings = []
499
+
500
+ try:
501
+ content = file_path.read_text(encoding="utf-8")
502
+ lines = content.splitlines()
503
+
504
+ for i, line in enumerate(lines, 1):
505
+ # Look for misconfigurations in source code
506
+ if any(
507
+ debug_pattern in line.lower()
508
+ for debug_pattern in ["debug=true", "debug: true", "enable_debug", "app.debug"]
509
+ ):
510
+ if any(on_val in line.lower() for on_val in ["true", "1", "yes", "on"]):
511
+ findings.append(
512
+ make_finding(
513
+ severity=Severity.HIGH,
514
+ file=rel_path,
515
+ line_start=i,
516
+ title="Debug Enabled in Source Code",
517
+ description="Debug mode enabled in source code",
518
+ evidence=line.strip(),
519
+ )
520
+ )
521
+
522
+ # Look for insecure CORS in source code
523
+ if any(
524
+ cors_pattern in line.lower()
525
+ for cors_pattern in ["cors.*[*]", "allow_all_origins", "origins=[*]"]
526
+ ):
527
+ findings.append(
528
+ make_finding(
529
+ severity=Severity.HIGH,
530
+ file=rel_path,
531
+ line_start=i,
532
+ title="Insecure CORS Configuration",
533
+ description="Insecure CORS configuration in source code",
534
+ evidence=line.strip(),
535
+ )
536
+ )
537
+
538
+ # Look for missing security headers
539
+ if any(
540
+ header_pattern in line.lower()
541
+ for header_pattern in [
542
+ "x-frame-options",
543
+ "frame_options",
544
+ "content-security-policy",
545
+ ]
546
+ ):
547
+ if any(
548
+ off_pattern in line.lower()
549
+ for off_pattern in ["sameorigin", "deny", "default-src"]
550
+ ):
551
+ # These are generally secure settings
552
+ pass
553
+ else:
554
+ # Check if the header is disabled
555
+ if any(
556
+ disable_pattern in line.lower()
557
+ for disable_pattern in ["none", "null", "empty", "unset"]
558
+ ):
559
+ findings.append(
560
+ make_finding(
561
+ severity=Severity.MEDIUM,
562
+ file=rel_path,
563
+ line_start=i,
564
+ title="Missing Security Header",
565
+ description="Security header may not be properly set",
566
+ evidence=line.strip(),
567
+ )
568
+ )
569
+
570
+ except Exception as e:
571
+ findings.append(
572
+ make_finding(
573
+ severity=Severity.LOW,
574
+ file=rel_path,
575
+ line_start=0,
576
+ title="Misconfig scanner source file read error",
577
+ description=f"Could not analyze {file_path.name} for misconfigurations: {str(e)}",
578
+ evidence=str(e),
579
+ )
580
+ )
581
+
582
+ return findings
583
+
584
+ def _find_nested_key(self, data, keys, condition=None):
585
+ """Helper to find nested keys in config data."""
586
+ if isinstance(data, dict):
587
+ for key, value in data.items():
588
+ if key in keys:
589
+ if condition is None or condition(value):
590
+ return True
591
+ # Recursively search nested dicts
592
+ if isinstance(value, (dict, list)):
593
+ if self._find_nested_key(value, keys, condition):
594
+ return True
595
+ elif isinstance(data, list):
596
+ for item in data:
597
+ if isinstance(item, (dict, list)):
598
+ if self._find_nested_key(item, keys, condition):
599
+ return True
600
+ return False