legate 0.1.0

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 (317) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +345 -0
  4. data/bin/legate +13 -0
  5. data/examples/00_quickstart.rb +51 -0
  6. data/examples/01_simple_agent.rb +105 -0
  7. data/examples/02_multi_tool_agent.rb +140 -0
  8. data/examples/03_custom_tool.rb +93 -0
  9. data/examples/04_agent_instructions.rb +84 -0
  10. data/examples/05_state_and_sessions.rb +91 -0
  11. data/examples/06_callbacks.rb +186 -0
  12. data/examples/07_async_jobs.rb +112 -0
  13. data/examples/08_loop_agent.rb +197 -0
  14. data/examples/09_sequential_workflow.rb +40 -0
  15. data/examples/10_parallel_workflow.rb +34 -0
  16. data/examples/11_agent_delegation.rb +24 -0
  17. data/examples/12_http_client_tool.rb +156 -0
  18. data/examples/13_authentication.rb +220 -0
  19. data/examples/14_mcp_client.rb +154 -0
  20. data/examples/15_mcp_server.rb +79 -0
  21. data/examples/16_webhooks.rb +91 -0
  22. data/examples/README_sequential_agents.md +164 -0
  23. data/examples/advanced/auth/cookie_auth_tool.rb +146 -0
  24. data/examples/advanced/auth/custom_auth_flows_example.rb +626 -0
  25. data/examples/advanced/auth/excon_middleware.rb +317 -0
  26. data/examples/advanced/auth/excon_middleware_auth.rb +399 -0
  27. data/examples/advanced/auth/fiber_auth_example.rb +281 -0
  28. data/examples/advanced/auth/fiber_oidc_example.rb +403 -0
  29. data/examples/advanced/auth/httpbin_bearer_tool.rb +159 -0
  30. data/examples/advanced/auth/oauth2_auth.rb +419 -0
  31. data/examples/advanced/auth/oidc_auth.rb +514 -0
  32. data/examples/advanced/auth/openweather_api.rb +251 -0
  33. data/examples/advanced/auth/openweather_tool.rb +153 -0
  34. data/examples/advanced/auth/query_param_middleware_test.rb +138 -0
  35. data/examples/advanced/auth/service_account.rb +135 -0
  36. data/examples/advanced/auth/test_with_httpbin.rb +202 -0
  37. data/examples/advanced/auth/token_lifecycle_example.rb +428 -0
  38. data/examples/advanced/callback_monitoring.rb +679 -0
  39. data/examples/advanced/mas/fixed_delegation_example.rb +191 -0
  40. data/examples/advanced/mas/loop_workflow.rb +28 -0
  41. data/examples/advanced/mas/mock_planner.rb +77 -0
  42. data/examples/advanced/mas/proper_delegation_example.rb +276 -0
  43. data/examples/advanced/mcp/legate_mcp_server_resource_example.rb +182 -0
  44. data/examples/advanced/mcp/mcp_resource_server_example.rb +309 -0
  45. data/examples/advanced/mcp/mcp_server_async.rb +76 -0
  46. data/examples/advanced/mcp/mcp_server_async_tools.rb +122 -0
  47. data/examples/advanced/mcp/mcp_server_legate_agent.rb +95 -0
  48. data/examples/advanced/mcp/mcp_server_rack.rb +89 -0
  49. data/examples/advanced/random_calculator.rb +104 -0
  50. data/examples/advanced/sleep_agent.rb +153 -0
  51. data/examples/advanced/webhooks/webhook_e2e_runner.rb +110 -0
  52. data/examples/advanced/webhooks/webhook_receiver_agent.rb +58 -0
  53. data/examples/advanced/workflows/task_refinement_loop_agent.rb +278 -0
  54. data/examples/advanced/workflows/travel_planner_auto_sequential.rb +444 -0
  55. data/examples/advanced/workflows/travel_planner_parallel.rb +656 -0
  56. data/examples/advanced/workflows/travel_planner_sequential.rb +512 -0
  57. data/examples/tools/oauth2_example.rb +136 -0
  58. data/examples/tools/sleepy_tool.rb +42 -0
  59. data/lib/legate/activity_log.rb +71 -0
  60. data/lib/legate/agent.rb +959 -0
  61. data/lib/legate/agent_code_generator.rb +185 -0
  62. data/lib/legate/agent_definition.rb +812 -0
  63. data/lib/legate/agentic/decision.rb +49 -0
  64. data/lib/legate/agentic/loop.rb +134 -0
  65. data/lib/legate/agentic.rb +5 -0
  66. data/lib/legate/agents/loop_agent.rb +248 -0
  67. data/lib/legate/agents/parallel_agent.rb +163 -0
  68. data/lib/legate/agents/sequential_agent.rb +190 -0
  69. data/lib/legate/agents.rb +14 -0
  70. data/lib/legate/auth/config.rb +148 -0
  71. data/lib/legate/auth/coordinator.rb +218 -0
  72. data/lib/legate/auth/coordinators/oauth2_coordinator.rb +99 -0
  73. data/lib/legate/auth/coordinators/oidc_coordinator.rb +68 -0
  74. data/lib/legate/auth/coordinators/service_account_coordinator.rb +122 -0
  75. data/lib/legate/auth/credential.rb +157 -0
  76. data/lib/legate/auth/encryption.rb +108 -0
  77. data/lib/legate/auth/error.rb +94 -0
  78. data/lib/legate/auth/exchanged_credential.rb +180 -0
  79. data/lib/legate/auth/excon_middleware.rb +285 -0
  80. data/lib/legate/auth/http_client_utils.rb +364 -0
  81. data/lib/legate/auth/manager.rb +531 -0
  82. data/lib/legate/auth/manager_store.rb +394 -0
  83. data/lib/legate/auth/middleware_factory.rb +290 -0
  84. data/lib/legate/auth/runner.rb +279 -0
  85. data/lib/legate/auth/scheme.rb +125 -0
  86. data/lib/legate/auth/schemes/api_key.rb +212 -0
  87. data/lib/legate/auth/schemes/google_service_account.rb +108 -0
  88. data/lib/legate/auth/schemes/http_bearer.rb +98 -0
  89. data/lib/legate/auth/schemes/oauth2.rb +396 -0
  90. data/lib/legate/auth/schemes/openid_connect.rb +346 -0
  91. data/lib/legate/auth/schemes/service_account.rb +388 -0
  92. data/lib/legate/auth/schemes.rb +40 -0
  93. data/lib/legate/auth/token_manager.rb +362 -0
  94. data/lib/legate/auth/token_store.rb +86 -0
  95. data/lib/legate/auth/tool_context_extension.rb +97 -0
  96. data/lib/legate/auth/tool_integration.rb +188 -0
  97. data/lib/legate/auth/url_guard.rb +81 -0
  98. data/lib/legate/auth.rb +453 -0
  99. data/lib/legate/callbacks/callback_context.rb +71 -0
  100. data/lib/legate/cli/agent_commands.rb +950 -0
  101. data/lib/legate/cli/auth_commands.rb +520 -0
  102. data/lib/legate/cli/base_command.rb +24 -0
  103. data/lib/legate/cli/deployment_commands.rb +934 -0
  104. data/lib/legate/cli/output_helper.rb +108 -0
  105. data/lib/legate/cli/session_commands.rb +138 -0
  106. data/lib/legate/cli/skaffold_commands.rb +223 -0
  107. data/lib/legate/cli/tool_commands.rb +261 -0
  108. data/lib/legate/cli/web_commands.rb +182 -0
  109. data/lib/legate/cli.rb +40 -0
  110. data/lib/legate/configuration/webhooks.rb +113 -0
  111. data/lib/legate/configuration.rb +39 -0
  112. data/lib/legate/definition_store.rb +23 -0
  113. data/lib/legate/errors.rb +118 -0
  114. data/lib/legate/event.rb +161 -0
  115. data/lib/legate/gemini_ai_beta_patch.rb +39 -0
  116. data/lib/legate/generators/agent_generator.rb +412 -0
  117. data/lib/legate/generators/code_validator.rb +48 -0
  118. data/lib/legate/generators/legate/install_generator.rb +35 -0
  119. data/lib/legate/generators/legate/templates/create_legate_tables.rb.tt +36 -0
  120. data/lib/legate/generators/legate/templates/initializer.rb +18 -0
  121. data/lib/legate/generators/runtime_tool_loader.rb +76 -0
  122. data/lib/legate/generators/tool_generator.rb +408 -0
  123. data/lib/legate/generators.rb +11 -0
  124. data/lib/legate/global_definition_registry.rb +506 -0
  125. data/lib/legate/global_tool_manager.rb +135 -0
  126. data/lib/legate/llm/adapter.rb +69 -0
  127. data/lib/legate/llm/gemini.rb +172 -0
  128. data/lib/legate/llm/ollama.rb +80 -0
  129. data/lib/legate/llm.rb +34 -0
  130. data/lib/legate/mcp/client.rb +320 -0
  131. data/lib/legate/mcp/connection/sse.rb +292 -0
  132. data/lib/legate/mcp/connection/stdio.rb +273 -0
  133. data/lib/legate/mcp/connection_manager.rb +103 -0
  134. data/lib/legate/mcp/server/legate_agent_adapter.rb +170 -0
  135. data/lib/legate/mcp/server/legate_direct_agent_adapter.rb +140 -0
  136. data/lib/legate/mcp/server/legate_tool_adapter.rb +119 -0
  137. data/lib/legate/mcp/tool_wrapper.rb +138 -0
  138. data/lib/legate/mcp/util/schema_converter.rb +134 -0
  139. data/lib/legate/mcp.rb +23 -0
  140. data/lib/legate/plan_executor.rb +375 -0
  141. data/lib/legate/planner.rb +839 -0
  142. data/lib/legate/rails/railtie.rb +43 -0
  143. data/lib/legate/rails.rb +9 -0
  144. data/lib/legate/redaction.rb +32 -0
  145. data/lib/legate/session.rb +299 -0
  146. data/lib/legate/session_service/active_record.rb +300 -0
  147. data/lib/legate/session_service/base.rb +68 -0
  148. data/lib/legate/session_service/event_broadcast.rb +74 -0
  149. data/lib/legate/session_service/in_memory.rb +188 -0
  150. data/lib/legate/tool/metadata_dsl.rb +122 -0
  151. data/lib/legate/tool.rb +276 -0
  152. data/lib/legate/tool_code_generator.rb +103 -0
  153. data/lib/legate/tool_context.rb +350 -0
  154. data/lib/legate/tool_loader.rb +39 -0
  155. data/lib/legate/tool_registry.rb +73 -0
  156. data/lib/legate/tool_result.rb +61 -0
  157. data/lib/legate/tools/agent_tool.rb +187 -0
  158. data/lib/legate/tools/base/http_client.rb +319 -0
  159. data/lib/legate/tools/base/safe_url.rb +56 -0
  160. data/lib/legate/tools/base_async_job_tool.rb +91 -0
  161. data/lib/legate/tools/calculator.rb +89 -0
  162. data/lib/legate/tools/cat_facts.rb +81 -0
  163. data/lib/legate/tools/check_job_status_tool.rb +48 -0
  164. data/lib/legate/tools/current_time_tool.rb +64 -0
  165. data/lib/legate/tools/echo.rb +43 -0
  166. data/lib/legate/tools/http_request_tool.rb +105 -0
  167. data/lib/legate/tools/random_number_tool.rb +64 -0
  168. data/lib/legate/tools/read_webpage_tool.rb +92 -0
  169. data/lib/legate/tools/sleepy_tool.rb +74 -0
  170. data/lib/legate/tools/webhook_tool.rb +146 -0
  171. data/lib/legate/version.rb +5 -0
  172. data/lib/legate/web/app.rb +984 -0
  173. data/lib/legate/web/public/css/main.css +4980 -0
  174. data/lib/legate/web/public/images/favicon-256.png +0 -0
  175. data/lib/legate/web/public/images/favicon-32.png +0 -0
  176. data/lib/legate/web/public/images/legate-logo-dark.png +0 -0
  177. data/lib/legate/web/public/images/legate-logo-light.png +0 -0
  178. data/lib/legate/web/public/js/legate.js +616 -0
  179. data/lib/legate/web/public/styles/main.scss +4402 -0
  180. data/lib/legate/web/routes/agent_authentication_routes.rb +530 -0
  181. data/lib/legate/web/routes/agent_definition_routes.rb +803 -0
  182. data/lib/legate/web/routes/agent_generator_routes.rb +80 -0
  183. data/lib/legate/web/routes/agent_interaction_routes.rb +734 -0
  184. data/lib/legate/web/routes/agent_runtime_routes.rb +323 -0
  185. data/lib/legate/web/routes/api_routes.rb +56 -0
  186. data/lib/legate/web/routes/authentication_routes.rb +1541 -0
  187. data/lib/legate/web/routes/core_routes.rb +111 -0
  188. data/lib/legate/web/routes/documentation_routes.rb +220 -0
  189. data/lib/legate/web/routes/tool_generator_routes.rb +81 -0
  190. data/lib/legate/web/routes/tools_ui_routes.rb +207 -0
  191. data/lib/legate/web/sass_compiler.rb +73 -0
  192. data/lib/legate/web/views/_active_session_info.slim +25 -0
  193. data/lib/legate/web/views/_activity_list.slim +55 -0
  194. data/lib/legate/web/views/_agent_card.slim +56 -0
  195. data/lib/legate/web/views/_agent_generator_modal.slim +382 -0
  196. data/lib/legate/web/views/_agent_status_controls.slim +71 -0
  197. data/lib/legate/web/views/_agent_tool_table.slim +74 -0
  198. data/lib/legate/web/views/_chat_message.slim +95 -0
  199. data/lib/legate/web/views/_display_agent_configuration.slim +26 -0
  200. data/lib/legate/web/views/_display_agent_description.slim +11 -0
  201. data/lib/legate/web/views/_display_agent_fallback.slim +15 -0
  202. data/lib/legate/web/views/_display_agent_hierarchy.slim +93 -0
  203. data/lib/legate/web/views/_display_agent_instruction.slim +17 -0
  204. data/lib/legate/web/views/_display_agent_mcp.slim +13 -0
  205. data/lib/legate/web/views/_display_agent_model.slim +17 -0
  206. data/lib/legate/web/views/_display_agent_name.slim +42 -0
  207. data/lib/legate/web/views/_display_agent_output_key.slim +26 -0
  208. data/lib/legate/web/views/_display_agent_type.slim +65 -0
  209. data/lib/legate/web/views/_edit_agent_configuration.slim +74 -0
  210. data/lib/legate/web/views/_edit_agent_description.slim +16 -0
  211. data/lib/legate/web/views/_edit_agent_fallback.slim +25 -0
  212. data/lib/legate/web/views/_edit_agent_hierarchy.slim +98 -0
  213. data/lib/legate/web/views/_edit_agent_instruction.slim +49 -0
  214. data/lib/legate/web/views/_edit_agent_mcp.slim +33 -0
  215. data/lib/legate/web/views/_edit_agent_model.slim +23 -0
  216. data/lib/legate/web/views/_edit_agent_output_key.slim +36 -0
  217. data/lib/legate/web/views/_edit_agent_tools.slim +40 -0
  218. data/lib/legate/web/views/_edit_agent_type.slim +67 -0
  219. data/lib/legate/web/views/_session_error.slim +4 -0
  220. data/lib/legate/web/views/_skeleton.slim +69 -0
  221. data/lib/legate/web/views/_tool_card.slim +9 -0
  222. data/lib/legate/web/views/_tool_generator_modal.slim +311 -0
  223. data/lib/legate/web/views/agent.slim +436 -0
  224. data/lib/legate/web/views/agent_auth.slim +562 -0
  225. data/lib/legate/web/views/agents.slim +369 -0
  226. data/lib/legate/web/views/auth.slim +112 -0
  227. data/lib/legate/web/views/auth_credential_detail.slim +327 -0
  228. data/lib/legate/web/views/auth_credentials.slim +261 -0
  229. data/lib/legate/web/views/auth_debug.slim +94 -0
  230. data/lib/legate/web/views/auth_mapping_detail.slim +151 -0
  231. data/lib/legate/web/views/auth_mapping_new.slim +123 -0
  232. data/lib/legate/web/views/auth_mappings.slim +120 -0
  233. data/lib/legate/web/views/auth_scheme_detail.slim +274 -0
  234. data/lib/legate/web/views/auth_schemes.slim +259 -0
  235. data/lib/legate/web/views/auth_test.slim +418 -0
  236. data/lib/legate/web/views/chat.slim +192 -0
  237. data/lib/legate/web/views/docs_index.slim +105 -0
  238. data/lib/legate/web/views/docs_show.slim +105 -0
  239. data/lib/legate/web/views/error_404.slim +5 -0
  240. data/lib/legate/web/views/index.slim +148 -0
  241. data/lib/legate/web/views/layout.slim +144 -0
  242. data/lib/legate/web/views/tool_detail.slim +87 -0
  243. data/lib/legate/web/views/tools.slim +50 -0
  244. data/lib/legate/web/webhook_listener.rb +367 -0
  245. data/lib/legate/web.rb +9 -0
  246. data/lib/legate.rb +220 -0
  247. data/public/docs/advanced/callbacks.md +828 -0
  248. data/public/docs/advanced/mcp_schema_conversion.md +59 -0
  249. data/public/docs/authentication/api_reference/config.md +210 -0
  250. data/public/docs/authentication/api_reference/credential.md +246 -0
  251. data/public/docs/authentication/api_reference/encryption.md +218 -0
  252. data/public/docs/authentication/api_reference/exchanged_credential.md +271 -0
  253. data/public/docs/authentication/api_reference/excon_middleware.md +175 -0
  254. data/public/docs/authentication/api_reference/index.md +30 -0
  255. data/public/docs/authentication/api_reference/scheme.md +250 -0
  256. data/public/docs/authentication/api_reference/schemes/api_key.md +175 -0
  257. data/public/docs/authentication/api_reference/schemes/google_service_account.md +221 -0
  258. data/public/docs/authentication/api_reference/schemes/http_bearer.md +169 -0
  259. data/public/docs/authentication/api_reference/schemes/oauth2.md +343 -0
  260. data/public/docs/authentication/api_reference/schemes/oidc.md +73 -0
  261. data/public/docs/authentication/api_reference/schemes/openid_connect.md +311 -0
  262. data/public/docs/authentication/api_reference/schemes/service_account.md +287 -0
  263. data/public/docs/authentication/api_reference/token_manager.md +221 -0
  264. data/public/docs/authentication/api_reference/token_store.md +146 -0
  265. data/public/docs/authentication/api_reference/tool_context_extension.md +166 -0
  266. data/public/docs/authentication/guides/api_key.md +190 -0
  267. data/public/docs/authentication/guides/bearer.md +172 -0
  268. data/public/docs/authentication/guides/configuration.md +255 -0
  269. data/public/docs/authentication/guides/custom_flow.md +523 -0
  270. data/public/docs/authentication/guides/index.md +24 -0
  271. data/public/docs/authentication/guides/migration.md +435 -0
  272. data/public/docs/authentication/guides/oauth2.md +252 -0
  273. data/public/docs/authentication/guides/oidc.md +241 -0
  274. data/public/docs/authentication/guides/overview.md +155 -0
  275. data/public/docs/authentication/guides/secure_storage.md +301 -0
  276. data/public/docs/authentication/guides/service_account.md +228 -0
  277. data/public/docs/authentication/guides/token_lifecycle.md +295 -0
  278. data/public/docs/authentication/guides/web_ui_integration.md +504 -0
  279. data/public/docs/authentication/index.md +58 -0
  280. data/public/docs/authentication/troubleshooting/credential_storage.md +550 -0
  281. data/public/docs/authentication/troubleshooting/environment_variables.md +540 -0
  282. data/public/docs/authentication/troubleshooting/index.md +11 -0
  283. data/public/docs/authentication/troubleshooting/oauth2_issues.md +220 -0
  284. data/public/docs/authentication/troubleshooting/oidc_issues.md +412 -0
  285. data/public/docs/authentication/troubleshooting/token_refresh.md +338 -0
  286. data/public/docs/cli/legate_cli_usage.md +363 -0
  287. data/public/docs/core_concepts/legate_agent_lifecycle.md +124 -0
  288. data/public/docs/core_concepts/legate_architecture_overview.md +110 -0
  289. data/public/docs/core_concepts/legate_configuration.md +116 -0
  290. data/public/docs/core_concepts/legate_definition_store.md +102 -0
  291. data/public/docs/core_concepts/legate_planner.md +94 -0
  292. data/public/docs/core_concepts/legate_session_service.md +104 -0
  293. data/public/docs/error_handling/legate_error_handling.md +122 -0
  294. data/public/docs/examples.md +199 -0
  295. data/public/docs/getting_started.md +111 -0
  296. data/public/docs/guides/agentic_agents.md +137 -0
  297. data/public/docs/guides/ai_code_generators.md +437 -0
  298. data/public/docs/guides/auto_loading.md +326 -0
  299. data/public/docs/guides/configuring_agent_webhooks.md +219 -0
  300. data/public/docs/guides/http_client_usage.md +264 -0
  301. data/public/docs/guides/llm_providers.md +137 -0
  302. data/public/docs/guides/mcp_client_integration.md +232 -0
  303. data/public/docs/guides/mcp_server_exposure.md +206 -0
  304. data/public/docs/guides/rails_integration.md +128 -0
  305. data/public/docs/guides/sending_outbound_webhooks.md +227 -0
  306. data/public/docs/guides/streaming.md +112 -0
  307. data/public/docs/guides/webhooks.md +288 -0
  308. data/public/docs/introduction.md +51 -0
  309. data/public/docs/multi_agent_systems/advanced_features.md +57 -0
  310. data/public/docs/multi_agent_systems/agent_delegation.md +190 -0
  311. data/public/docs/multi_agent_systems/agent_hierarchy.md +49 -0
  312. data/public/docs/multi_agent_systems/state_management.md +47 -0
  313. data/public/docs/multi_agent_systems/workflow_agents.md +72 -0
  314. data/public/docs/tools/legate_built_in_tools.md +332 -0
  315. data/public/docs/tools/legate_tools_and_registry.md +263 -0
  316. data/public/docs/web_ui/legate_web_ui.md +137 -0
  317. metadata +823 -0
@@ -0,0 +1,364 @@
1
+ # File: lib/legate/auth/http_client_utils.rb
2
+ # frozen_string_literal: true
3
+
4
+ require 'excon'
5
+ require_relative 'excon_middleware'
6
+ require_relative 'middleware_factory'
7
+
8
+ module Legate
9
+ module Auth
10
+ # Utility module for integrating authentication with HTTP clients.
11
+ # Provides methods for configuring Excon clients with authentication middleware.
12
+ module HttpClientUtils
13
+ class << self
14
+ # Configure an Excon connection with authentication middleware
15
+ # @param connection [Excon::Connection] The Excon connection to configure
16
+ # @param scheme [Legate::Auth::Scheme] The authentication scheme
17
+ # @param credential [Legate::Auth::Credential] The credential
18
+ # @param options [Hash] Additional options for the middleware
19
+ # @return [Excon::Connection] The configured connection
20
+ def configure_connection(connection, scheme:, credential:, **options)
21
+ # Create the middleware
22
+ middleware = MiddlewareFactory.create(scheme: scheme, credential: credential, **options)
23
+
24
+ # Add the middleware to the connection
25
+ connection.data[:middlewares] ||= connection.data[:middlewares].dup
26
+
27
+ # Remove any existing auth middleware of the same type
28
+ connection.data[:middlewares].reject! { |m| m == middleware.class }
29
+
30
+ # Add our middleware - ensure it's actually added to the stack
31
+ connection.data[:middlewares] << middleware.class unless connection.data[:middlewares].include?(middleware.class)
32
+
33
+ # Store the middleware instance in the connection
34
+ connection.data[:auth_middleware] = middleware
35
+
36
+ connection
37
+ end
38
+
39
+ # Create a new Excon connection with authentication middleware
40
+ # @param url [String] The URL for the connection
41
+ # @param scheme [Legate::Auth::Scheme] The authentication scheme
42
+ # @param credential [Legate::Auth::Credential] The credential
43
+ # @param options [Hash] Additional options for the Excon connection and middleware
44
+ # @return [Excon::Connection] The configured connection
45
+ def create_connection(url, scheme:, credential:, **options)
46
+ # Extract middleware options from the options hash
47
+ middleware_options = extract_middleware_options(options)
48
+
49
+ # Create the connection
50
+ connection = Excon.new(url, options)
51
+
52
+ # Configure the connection with authentication
53
+ configure_connection(connection, scheme: scheme, credential: credential, **middleware_options)
54
+ end
55
+
56
+ # Create a new Excon connection with API key authentication
57
+ # @param url [String] The URL for the connection
58
+ # @param api_key [String] The API key
59
+ # @param location [String] Where to place the API key ('header', 'query', 'cookie')
60
+ # @param name [String] The name of the parameter/header
61
+ # @param options [Hash] Additional options for the Excon connection and middleware
62
+ # @return [Excon::Connection] The configured connection
63
+ def create_api_key_connection(url, api_key:, location: 'header', name: 'X-API-Key', **options)
64
+ # Create the scheme
65
+ scheme = Legate::Auth::Schemes::ApiKey.new
66
+
67
+ # Create the credential
68
+ credential = Legate::Auth::Credential.new(
69
+ auth_type: :api_key,
70
+ api_key: api_key,
71
+ location: location,
72
+ name: name
73
+ )
74
+
75
+ # Extract middleware options from the options hash
76
+ middleware_options = extract_middleware_options(options)
77
+
78
+ # Create the middleware using the factory
79
+ middleware_instance = MiddlewareFactory.create(
80
+ scheme: scheme,
81
+ credential: credential,
82
+ **middleware_options
83
+ )
84
+
85
+ # Prepare Excon options, ensuring we don't modify the original options hash directly
86
+ excon_opts = options.dup
87
+ # Remove our custom options that shouldn't be passed directly to Excon.new if they were in **options
88
+ excon_opts.delete(:token_store) # Example, add others if necessary
89
+ excon_opts.delete(:token_manager)
90
+ excon_opts.delete(:session_service) # if MiddlewareFactory might add it to options
91
+ # also retry options if they are only for our middleware and not excon directly
92
+ %i[auto_retry max_retries backoff_strategy backoff_factor retry_non_idempotent retry_on].each do |k|
93
+ excon_opts.delete(k)
94
+ end
95
+
96
+ # Add retry configuration for Idempotent middleware
97
+ excon_opts[:retry_limit] = 3
98
+ excon_opts[:retry_interval] = 0.5
99
+ excon_opts[:idempotent] = true
100
+
101
+ # Ensure SSL verification is enabled
102
+ excon_opts[:ssl_verify_peer] = true
103
+
104
+ # Increase default timeouts if not specified
105
+ excon_opts[:connect_timeout] ||= 30
106
+ excon_opts[:read_timeout] ||= 30
107
+ excon_opts[:write_timeout] ||= 30
108
+
109
+ # Create the connection with our middleware
110
+ connection = Excon.new(url, excon_opts)
111
+
112
+ # Configure the middleware stack
113
+ connection.data[:middlewares] ||= connection.data[:middlewares].dup
114
+ connection.data[:middlewares].reject! { |m| m == Legate::Auth::ExconMiddleware }
115
+
116
+ # Add our middleware class to the stack
117
+ unless connection.data[:middlewares].include?(Legate::Auth::ExconMiddleware)
118
+ # Find the position after Idempotent middleware
119
+ idempotent_index = connection.data[:middlewares].index(Excon::Middleware::Idempotent)
120
+ if idempotent_index
121
+ connection.data[:middlewares].insert(idempotent_index + 1, Legate::Auth::ExconMiddleware)
122
+ else
123
+ connection.data[:middlewares] << Legate::Auth::ExconMiddleware
124
+ end
125
+ end
126
+
127
+ # Store the middleware configuration for use by the shell instance
128
+ connection.data[:auth_middleware_config] = middleware_instance
129
+
130
+ connection
131
+ end
132
+
133
+ # Create a new Excon connection with bearer token authentication
134
+ # @param url [String] The URL for the connection
135
+ # @param token [String] The bearer token
136
+ # @param options [Hash] Additional options for the Excon connection and middleware
137
+ # @return [Excon::Connection] The configured connection
138
+ def create_bearer_connection(url, token:, **options)
139
+ # Extract middleware options from the options hash
140
+ middleware_options = extract_middleware_options(options)
141
+
142
+ # Create middleware using the factory
143
+ middleware = MiddlewareFactory.create_bearer(
144
+ token: token,
145
+ **middleware_options
146
+ )
147
+
148
+ # Create the connection
149
+ connection = Excon.new(url, options)
150
+
151
+ # Add the middleware to the connection
152
+ connection.data[:middlewares] ||= connection.data[:middlewares].dup
153
+ connection.data[:middlewares].reject! { |m| m == Legate::Auth::ExconMiddleware }
154
+ connection.data[:middlewares] << middleware.class unless connection.data[:middlewares].include?(middleware.class)
155
+
156
+ # Store the middleware instance in the connection
157
+ connection.data[:auth_middleware] = middleware
158
+
159
+ connection
160
+ end
161
+
162
+ # Create a new Excon connection with OAuth2 authentication
163
+ # @param url [String] The URL for the connection
164
+ # @param client_id [String] The OAuth client ID
165
+ # @param client_secret [String] The OAuth client secret
166
+ # @param authorization_url [String] The authorization URL for the OAuth provider
167
+ # @param token_url [String] The token URL for the OAuth provider
168
+ # @param scopes [Array<String>, String, nil] The scopes to request
169
+ # @param options [Hash] Additional options for the middleware and connection
170
+ # @return [Excon::Connection] The configured connection
171
+ def create_oauth2_connection(url, client_id:, client_secret:, authorization_url:, token_url:, scopes: nil, **options)
172
+ # Extract middleware options from the options hash
173
+ middleware_options = extract_middleware_options(options)
174
+
175
+ # Create middleware using the factory
176
+ middleware = MiddlewareFactory.create_oauth2(
177
+ client_id: client_id,
178
+ client_secret: client_secret,
179
+ authorization_url: authorization_url,
180
+ token_url: token_url,
181
+ scopes: scopes,
182
+ **middleware_options
183
+ )
184
+
185
+ # Create the connection
186
+ connection = Excon.new(url, options)
187
+
188
+ # Add the middleware to the connection
189
+ connection.data[:middlewares] ||= connection.data[:middlewares].dup
190
+ connection.data[:middlewares].reject! { |m| m == Legate::Auth::ExconMiddleware }
191
+ connection.data[:middlewares] << middleware.class unless connection.data[:middlewares].include?(middleware.class)
192
+
193
+ # Store the middleware instance in the connection
194
+ connection.data[:auth_middleware] = middleware
195
+
196
+ connection
197
+ end
198
+
199
+ # Create a new Excon connection with service account authentication
200
+ # @param url [String] The URL for the connection
201
+ # @param service_account_key [String, Hash] The service account key
202
+ # @param scopes [Array<String>, String, nil] The scopes to request
203
+ # @param audience [String, nil] The audience for the token
204
+ # @param options [Hash] Additional options for the Excon connection and middleware
205
+ # @return [Excon::Connection] The configured connection
206
+ def create_service_account_connection(url, service_account_key:, scopes: nil, audience: nil, **options)
207
+ # Extract middleware options from the options hash
208
+ middleware_options = extract_middleware_options(options)
209
+
210
+ # Create middleware using the factory
211
+ middleware = MiddlewareFactory.create_service_account(
212
+ service_account_key: service_account_key,
213
+ scopes: scopes,
214
+ audience: audience,
215
+ **middleware_options
216
+ )
217
+
218
+ # Create the connection
219
+ connection = Excon.new(url, options)
220
+
221
+ # Add the middleware to the connection
222
+ connection.data[:middlewares] ||= connection.data[:middlewares].dup
223
+ connection.data[:middlewares].reject! { |m| m == Legate::Auth::ExconMiddleware }
224
+ connection.data[:middlewares] << middleware.class unless connection.data[:middlewares].include?(middleware.class)
225
+
226
+ # Store the middleware instance in the connection
227
+ connection.data[:auth_middleware] = middleware
228
+
229
+ connection
230
+ end
231
+
232
+ # Create a new Excon connection with OpenID Connect authentication
233
+ # @param url [String] The URL for the connection
234
+ # @param client_id [String] The OIDC client ID
235
+ # @param client_secret [String] The OIDC client secret
236
+ # @param discovery_url [String, nil] The OIDC discovery URL
237
+ # @param options [Hash] Additional options for the middleware and connection
238
+ # @return [Excon::Connection] The configured connection
239
+ def create_oidc_connection(url, client_id:, client_secret:, discovery_url:, **options)
240
+ # Extract middleware options from the options hash
241
+ middleware_options = extract_middleware_options(options)
242
+
243
+ # Create middleware using the factory
244
+ middleware = MiddlewareFactory.create_oidc(
245
+ client_id: client_id,
246
+ client_secret: client_secret,
247
+ discovery_url: discovery_url,
248
+ **middleware_options
249
+ )
250
+
251
+ # Create the connection
252
+ connection = Excon.new(url, options)
253
+
254
+ # Add the middleware to the connection
255
+ connection.data[:middlewares] ||= connection.data[:middlewares].dup
256
+ connection.data[:middlewares].reject! { |m| m == Legate::Auth::ExconMiddleware }
257
+ connection.data[:middlewares] << middleware.class unless connection.data[:middlewares].include?(middleware.class)
258
+
259
+ # Store the middleware instance in the connection
260
+ connection.data[:auth_middleware] = middleware
261
+
262
+ connection
263
+ end
264
+
265
+ # Create a new Excon connection with Basic authentication
266
+ # @param url [String] The URL for the connection
267
+ # @param username [String] The username
268
+ # @param password [String] The password
269
+ # @param options [Hash] Additional options for the middleware and connection
270
+ # @return [Excon::Connection] The configured connection
271
+ def create_basic_auth_connection(url, username:, password:, **options)
272
+ # Extract middleware options from the options hash
273
+ middleware_options = extract_middleware_options(options)
274
+
275
+ # Create middleware using the factory
276
+ middleware = MiddlewareFactory.create_basic_auth(
277
+ username: username,
278
+ password: password,
279
+ **middleware_options
280
+ )
281
+
282
+ # Create the connection
283
+ connection = Excon.new(url, options)
284
+
285
+ # Add the middleware to the connection
286
+ connection.data[:middlewares] ||= connection.data[:middlewares].dup
287
+ connection.data[:middlewares].reject! { |m| m == Legate::Auth::ExconMiddleware }
288
+ connection.data[:middlewares] << middleware.class unless connection.data[:middlewares].include?(middleware.class)
289
+
290
+ # Store the middleware instance in the connection
291
+ connection.data[:auth_middleware] = middleware
292
+
293
+ connection
294
+ end
295
+
296
+ # Create a new Excon connection from a pre-configured authentication provider
297
+ # @param url [String] The URL for the connection
298
+ # @param provider_id [String] The ID of the pre-configured provider
299
+ # @param options [Hash] Additional options for the middleware and connection
300
+ # @return [Excon::Connection] The configured connection
301
+ def create_connection_from_provider(url, provider_id, **options)
302
+ # Extract middleware options from the options hash
303
+ middleware_options = extract_middleware_options(options)
304
+
305
+ # Create middleware using the factory
306
+ middleware = MiddlewareFactory.create_from_provider(
307
+ provider_id,
308
+ **middleware_options
309
+ )
310
+
311
+ # Create the connection
312
+ connection = Excon.new(url, options)
313
+
314
+ # Add the middleware to the connection
315
+ connection.data[:middlewares] ||= connection.data[:middlewares].dup
316
+ connection.data[:middlewares].reject! { |m| m == Legate::Auth::ExconMiddleware }
317
+ connection.data[:middlewares] << middleware.class unless connection.data[:middlewares].include?(middleware.class)
318
+
319
+ # Store the middleware instance in the connection
320
+ connection.data[:auth_middleware] = middleware
321
+
322
+ connection
323
+ end
324
+
325
+ # Apply authentication to a request using the given scheme and credential
326
+ # @param request [Hash] The request to authenticate
327
+ # @param scheme [Legate::Auth::Scheme] The authentication scheme
328
+ # @param credential [Legate::Auth::Credential] The credential
329
+ # @param options [Hash] Additional options for authentication
330
+ # @return [Hash] The authenticated request
331
+ def authenticate_request(request, scheme:, credential:, **options)
332
+ # Extract token store and manager from options
333
+ token_store = options[:token_store]
334
+ token_manager = options[:token_manager]
335
+
336
+ # Apply authentication
337
+ ToolIntegration.apply_authentication(request, scheme, credential, token_store, token_manager)
338
+ end
339
+
340
+ private
341
+
342
+ # Extract middleware-specific options from a combined options hash
343
+ # @param options [Hash] The combined options hash
344
+ # @return [Hash] The middleware-specific options
345
+ def extract_middleware_options(options)
346
+ middleware_keys = %i[
347
+ token_store token_manager auto_retry max_retries
348
+ backoff_strategy backoff_factor session_service
349
+ retry_non_idempotent retry_on token_lifetime
350
+ redirect_uri additional_params verify_id_token
351
+ ]
352
+
353
+ middleware_options = {}
354
+
355
+ middleware_keys.each do |key|
356
+ middleware_options[key] = options.delete(key) if options.key?(key)
357
+ end
358
+
359
+ middleware_options
360
+ end
361
+ end
362
+ end
363
+ end
364
+ end