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,550 @@
1
+ # Credential Storage Issues
2
+
3
+ This guide addresses common issues related to storing and managing authentication credentials in the Legate Ruby library.
4
+
5
+ ## Common Credential Storage Issues
6
+
7
+ ### Environment Variable Resolution
8
+
9
+ **Symptoms:**
10
+ - "Environment variable not found" errors
11
+ - Authentication failing despite credentials being set
12
+ - Credentials not being loaded correctly
13
+
14
+ **Possible Causes and Solutions:**
15
+
16
+ 1. **Missing Environment Variables**
17
+ ```ruby
18
+ # Problem: Environment variable referenced but not set
19
+
20
+ # Solution: Ensure environment variables are set before running
21
+ # In your shell:
22
+ export CLIENT_ID="your-client-id"
23
+ export CLIENT_SECRET="your-client-secret"
24
+
25
+ # In Ruby, verify environment variables are set
26
+ if ENV['CLIENT_ID'].nil? || ENV['CLIENT_SECRET'].nil?
27
+ puts "ERROR: Required environment variables are not set"
28
+ exit 1
29
+ end
30
+
31
+ # Then use in credential
32
+ credential = Legate::Auth::Credential.new(
33
+ auth_type: :oauth2,
34
+ client_id: 'ENV:CLIENT_ID',
35
+ client_secret: 'ENV:CLIENT_SECRET'
36
+ )
37
+ ```
38
+
39
+ 2. **Incorrect Environment Variable References**
40
+ ```ruby
41
+ # Problem: Incorrect prefix or format for environment variable reference
42
+
43
+ # Solution: Use the correct format with 'ENV:' prefix
44
+
45
+ # Incorrect:
46
+ credential = Legate::Auth::Credential.new(
47
+ auth_type: :oauth2,
48
+ client_id: ENV['CLIENT_ID'], # Direct reference, no resolution
49
+ client_secret: '${CLIENT_SECRET}' # Incorrect format
50
+ )
51
+
52
+ # Correct:
53
+ credential = Legate::Auth::Credential.new(
54
+ auth_type: :oauth2,
55
+ client_id: 'ENV:CLIENT_ID', # Proper environment variable reference
56
+ client_secret: 'ENV:CLIENT_SECRET'
57
+ )
58
+ ```
59
+
60
+ 3. **Environment Scope Issues**
61
+ ```ruby
62
+ # Problem: Environment variables not accessible to the process
63
+
64
+ # Solution: Verify environment variables are in the correct scope
65
+
66
+ # Check if variables are accessible
67
+ puts "CLIENT_ID: #{ENV['CLIENT_ID'] ? 'Set' : 'Not set'}"
68
+ puts "CLIENT_SECRET: #{ENV['CLIENT_SECRET'] ? 'Set' : 'Not set'}"
69
+
70
+ # For containerized applications, ensure variables are passed to the container
71
+ # docker run -e CLIENT_ID -e CLIENT_SECRET my-legate-app
72
+ ```
73
+
74
+ ### Secure Credential Storage
75
+
76
+ **Symptoms:**
77
+ - Security warnings about hardcoded credentials
78
+ - Credentials exposed in logs or errors
79
+ - Unauthorized access to sensitive credentials
80
+
81
+ **Possible Causes and Solutions:**
82
+
83
+ 1. **Hardcoded Credentials**
84
+ ```ruby
85
+ # Problem: Credentials hardcoded in source code
86
+
87
+ # Solution: Use environment variables or secure credential stores
88
+
89
+ # Incorrect (avoid this):
90
+ credential = Legate::Auth::Credential.new(
91
+ auth_type: :oauth2,
92
+ client_id: 'actual-client-id-123',
93
+ client_secret: 'actual-client-secret-456'
94
+ )
95
+
96
+ # Better:
97
+ credential = Legate::Auth::Credential.new(
98
+ auth_type: :oauth2,
99
+ client_id: 'ENV:CLIENT_ID',
100
+ client_secret: 'ENV:CLIENT_SECRET'
101
+ )
102
+
103
+ # Even better - resolve the secret from your own secrets manager
104
+ # (e.g. Vault, AWS Secrets Manager) before constructing the credential:
105
+ client_secret = MySecretsClient.fetch('oauth2_client_secret')
106
+
107
+ credential = Legate::Auth::Credential.new(
108
+ auth_type: :oauth2,
109
+ client_id: 'ENV:CLIENT_ID',
110
+ client_secret: client_secret
111
+ )
112
+ ```
113
+
114
+ 2. **Credential Logging**
115
+ ```ruby
116
+ # Problem: Sensitive credentials appear in logs
117
+
118
+ # Solution: Implement secure logging and avoid logging credentials
119
+
120
+ # Unsafe:
121
+ logger.info "Using credential: #{credential.to_h}"
122
+
123
+ # Better:
124
+ logger.info "Using credential type: #{credential.auth_type}"
125
+
126
+ # For debugging, sanitize sensitive fields:
127
+ safe_cred = credential.to_h
128
+ safe_cred[:client_secret] = "[REDACTED]" if safe_cred[:client_secret]
129
+ safe_cred[:api_key] = "[REDACTED]" if safe_cred[:api_key]
130
+ logger.debug "Using credential (sanitized): #{safe_cred}"
131
+ ```
132
+
133
+ 3. **Insecure Storage**
134
+ ```ruby
135
+ # Problem: Credentials stored insecurely on disk
136
+
137
+ # Solution: Use proper encryption for saved credentials
138
+
139
+ # Incorrect - storing credentials in plain text:
140
+ File.write('creds.json', JSON.dump(credential.to_h))
141
+
142
+ # Better - use the opt-in Encryption module (module methods, not instances).
143
+ # Requires the rbnacl gem and a Base64 key (see generate_key).
144
+ require 'legate/auth/encryption'
145
+
146
+ key = ENV['LEGATE_AUTH_ENCRYPTION_KEY'] # Base64-encoded; or Encryption.generate_key
147
+ encrypted_data = Legate::Auth::Encryption.encrypt(JSON.dump(credential.to_h), key)
148
+
149
+ # Store encrypted data
150
+ File.write('creds.enc', encrypted_data)
151
+
152
+ # Later, to decrypt:
153
+ encrypted_data = File.read('creds.enc')
154
+ json_data = Legate::Auth::Encryption.decrypt(encrypted_data, key)
155
+ cred_hash = JSON.parse(json_data)
156
+ ```
157
+
158
+ ### Session Storage Issues
159
+
160
+ **Symptoms:**
161
+ - Tokens disappearing between requests
162
+ - "Session not found" errors
163
+ - Authentication state not persisting
164
+
165
+ **Possible Causes and Solutions:**
166
+
167
+ 1. **Session Configuration**
168
+ ```ruby
169
+ # Problem: Session not configured properly
170
+
171
+ # Solution: Configure session with proper settings
172
+
173
+ # In a Sinatra app:
174
+ use Rack::Session::Cookie,
175
+ key: 'legate.session',
176
+ secret: ENV['SESSION_SECRET'],
177
+ expire_after: 86400 # 1 day in seconds
178
+
179
+ # In a Rails app:
180
+ # config/initializers/session_store.rb
181
+ Rails.application.config.session_store :cookie_store,
182
+ key: '_legate_session',
183
+ expire_after: 1.day
184
+ ```
185
+
186
+ 2. **Token Store Configuration**
187
+ ```ruby
188
+ # Problem: Token store not properly initialized
189
+
190
+ # Solution: Ensure token store is initialized with the session
191
+
192
+ # Incorrect:
193
+ token_store = Legate::Auth::TokenStore.new # Missing session service
194
+
195
+ # Correct: pass the session service positionally
196
+ token_store = Legate::Auth::TokenStore.new(session_service)
197
+
198
+ # Note: TokenStore.new takes a single positional argument (the session
199
+ # service). It does not accept namespace/serializer keyword options; tokens
200
+ # are stored under the fixed 'auth' scope.
201
+ ```
202
+
203
+ 3. **Session Expiration**
204
+ ```ruby
205
+ # Problem: Session expires before tokens are used
206
+
207
+ # Solution: Adjust session timeout or implement refresh mechanism
208
+
209
+ # Extend session timeout
210
+ use Rack::Session::Cookie,
211
+ key: 'legate.session',
212
+ secret: ENV['SESSION_SECRET'],
213
+ expire_after: 604800 # 1 week in seconds
214
+
215
+ # Or implement periodic session refresh
216
+ before do
217
+ # Refresh session on each request
218
+ session[:last_activity] = Time.now.to_i
219
+ end
220
+ ```
221
+
222
+ ## Encryption-Related Issues
223
+
224
+ **Symptoms:**
225
+ - "Decryption failed" errors
226
+ - "Invalid encryption key" errors
227
+ - Tokens cannot be retrieved from storage
228
+
229
+ **Possible Causes and Solutions:**
230
+
231
+ > **Note:** `Legate::Auth::Encryption` is an opt-in module (not wired into `TokenStore`) and is not instantiable — call its module methods directly. It uses rbnacl (libsodium SecretBox) and requires the `rbnacl` gem. Decryption failures raise `ArgumentError`; a missing `rbnacl` gem raises `LoadError`. There is no `EncryptionError` class and no algorithm option.
232
+
233
+ 1. **Encryption Key Issues**
234
+ ```ruby
235
+ # Problem: Missing or inconsistent encryption key
236
+
237
+ # Solution: Generate a Base64 key with generate_key and keep it consistent
238
+ require 'legate/auth/encryption'
239
+ encryption_key = Legate::Auth::Encryption.generate_key # Base64-encoded
240
+ puts "Generated encryption key: #{encryption_key}"
241
+
242
+ # Store this key securely (e.g. LEGATE_AUTH_ENCRYPTION_KEY) and reuse it
243
+ # consistently across app instances:
244
+ encrypted = Legate::Auth::Encryption.encrypt(data, ENV['LEGATE_AUTH_ENCRYPTION_KEY'])
245
+ ```
246
+
247
+ 2. **Wrong Key or Tampered Data**
248
+ ```ruby
249
+ # Problem: Decryption fails (wrong key, bad format, or tampered ciphertext)
250
+
251
+ # Solution: Decryption failures raise ArgumentError; handle them explicitly
252
+ begin
253
+ plaintext = Legate::Auth::Encryption.decrypt(encrypted_data, key)
254
+ rescue ArgumentError => e
255
+ puts "Decryption failed: #{e.message}"
256
+ end
257
+ ```
258
+
259
+ 3. **Key Rotation**
260
+ ```ruby
261
+ # Problem: Need to rotate encryption keys without losing data
262
+
263
+ # Solution: Implement key rotation with backward compatibility
264
+ def get_token_with_key_rotation(encrypted_data, key, legacy_key = nil)
265
+ begin
266
+ # Try with current key first
267
+ return Legate::Auth::Encryption.decrypt(encrypted_data, key)
268
+ rescue ArgumentError
269
+ raise unless legacy_key
270
+ # Try with legacy key, then re-encrypt with the new key
271
+ decrypted = Legate::Auth::Encryption.decrypt(encrypted_data, legacy_key)
272
+ new_encrypted = Legate::Auth::Encryption.encrypt(decrypted, key)
273
+ save_encrypted_data(new_encrypted)
274
+ decrypted
275
+ end
276
+ end
277
+ ```
278
+
279
+ ## Service Account Key Issues
280
+
281
+ **Symptoms:**
282
+ - "Invalid key format" errors
283
+ - JSON parsing errors with service account keys
284
+ - Authentication failing with service accounts
285
+
286
+ **Possible Causes and Solutions:**
287
+
288
+ 1. **JSON Key Format Issues**
289
+ ```ruby
290
+ # Problem: Service account key JSON is malformed
291
+
292
+ # Solution: Ensure JSON is valid and complete
293
+
294
+ # Verify key format
295
+ begin
296
+ key_data = JSON.parse(File.read('service-account-key.json'))
297
+ required_fields = ['type', 'project_id', 'private_key_id', 'private_key',
298
+ 'client_email', 'client_id', 'auth_uri', 'token_uri']
299
+
300
+ missing = required_fields - key_data.keys
301
+ if missing.any?
302
+ puts "Invalid key file: Missing fields: #{missing.join(', ')}"
303
+ else
304
+ puts "Key file appears valid"
305
+ end
306
+ rescue JSON::ParserError => e
307
+ puts "Invalid JSON: #{e.message}"
308
+ end
309
+ ```
310
+
311
+ 2. **Key Environment Variable Issues**
312
+ ```ruby
313
+ # Problem: Service account key environment variable is malformed
314
+
315
+ # Solution: Ensure JSON is properly escaped in the environment variable
316
+
317
+ # The environment variable must contain valid JSON:
318
+ # export SERVICE_ACCOUNT_JSON='{"type":"service_account","project_id":"...","private_key":"...","client_email":"..."}'
319
+
320
+ # In your code (pass the raw JSON string via service_account_key, not a
321
+ # parsed Hash; the attribute is service_account_key, not service_account_json):
322
+ service_account_json = ENV['SERVICE_ACCOUNT_JSON']
323
+ begin
324
+ JSON.parse(service_account_json) # validate it parses
325
+ rescue JSON::ParserError => e
326
+ puts "Invalid service account JSON in environment variable: #{e.message}"
327
+ end
328
+
329
+ credential = Legate::Auth::Credential.new(
330
+ auth_type: :service_account,
331
+ service_account_key: service_account_json # raw JSON string
332
+ )
333
+
334
+ # Or reference the env var directly:
335
+ # service_account_key: 'ENV:SERVICE_ACCOUNT_JSON'
336
+ ```
337
+
338
+ 3. **Key File Permissions**
339
+ ```ruby
340
+ # Problem: Key file has incorrect permissions
341
+
342
+ # Solution: Set restrictive file permissions
343
+
344
+ # In your terminal:
345
+ chmod 0600 service-account-key.json # Owner read/write only
346
+
347
+ # In your code, check permissions:
348
+ key_file = 'service-account-key.json'
349
+ permissions = File.stat(key_file).mode & 0777
350
+
351
+ if permissions > 0600
352
+ puts "WARNING: Key file permissions are too permissive: #{permissions.to_s(8)}"
353
+ puts "Consider restricting permissions with: chmod 0600 #{key_file}"
354
+ end
355
+ ```
356
+
357
+ ## Multi-Environment Configuration
358
+
359
+ **Symptoms:**
360
+ - Credentials work in development but fail in production
361
+ - Different behavior across environments
362
+ - Configuration errors in deployed applications
363
+
364
+ **Possible Causes and Solutions:**
365
+
366
+ 1. **Environment-Specific Credentials**
367
+ ```ruby
368
+ # Problem: Using the same credentials across environments
369
+
370
+ # Solution: Use environment-specific credential configuration
371
+
372
+ # Load different credentials based on environment
373
+ environment = ENV['RACK_ENV'] || 'development'
374
+
375
+ case environment
376
+ when 'development'
377
+ client_id = 'ENV:DEV_CLIENT_ID'
378
+ client_secret = 'ENV:DEV_CLIENT_SECRET'
379
+ when 'production'
380
+ client_id = 'ENV:PROD_CLIENT_ID'
381
+ client_secret = 'ENV:PROD_CLIENT_SECRET'
382
+ end
383
+
384
+ credential = Legate::Auth::Credential.new(
385
+ auth_type: :oauth2,
386
+ client_id: client_id,
387
+ client_secret: client_secret
388
+ )
389
+ ```
390
+
391
+ 2. **Configuration Loading Issues**
392
+ ```ruby
393
+ # Problem: Configuration not loaded in the correct order
394
+
395
+ # Solution: Establish clear configuration loading order
396
+
397
+ # Example configuration loader
398
+ def load_configuration
399
+ # 1. Load defaults
400
+ config = {
401
+ oauth2: {
402
+ client_id: nil,
403
+ client_secret: nil
404
+ }
405
+ }
406
+
407
+ # 2. Override with environment-specific configuration file
408
+ env_config_file = "config/#{ENV['RACK_ENV'] || 'development'}.yml"
409
+ if File.exist?(env_config_file)
410
+ env_config = YAML.load_file(env_config_file)
411
+ config.deep_merge!(env_config)
412
+ end
413
+
414
+ # 3. Override with environment variables
415
+ config[:oauth2][:client_id] = ENV['OAUTH_CLIENT_ID'] if ENV['OAUTH_CLIENT_ID']
416
+ config[:oauth2][:client_secret] = ENV['OAUTH_CLIENT_SECRET'] if ENV['OAUTH_CLIENT_SECRET']
417
+
418
+ config
419
+ end
420
+ ```
421
+
422
+ 3. **Environment Variable Names**
423
+ ```ruby
424
+ # Problem: Inconsistent environment variable naming across environments
425
+
426
+ # Solution: Standardize environment variable names
427
+
428
+ # Create a mapping between standard names and environment-specific names
429
+ env_var_mapping = {
430
+ development: {
431
+ client_id: 'DEV_CLIENT_ID',
432
+ client_secret: 'DEV_CLIENT_SECRET'
433
+ },
434
+ production: {
435
+ client_id: 'PROD_CLIENT_ID',
436
+ client_secret: 'PROD_CLIENT_SECRET'
437
+ }
438
+ }
439
+
440
+ environment = (ENV['RACK_ENV'] || 'development').to_sym
441
+ mapping = env_var_mapping[environment]
442
+
443
+ client_id = "ENV:#{mapping[:client_id]}"
444
+ client_secret = "ENV:#{mapping[:client_secret]}"
445
+ ```
446
+
447
+ ## Debugging Techniques
448
+
449
+ ### Credential Validation
450
+
451
+ For debugging credential issues:
452
+
453
+ ```ruby
454
+ # Validate a credential
455
+ def validate_credential(credential)
456
+ puts "Credential type: #{credential.auth_type}"
457
+
458
+ case credential.auth_type
459
+ when :oauth2, :oidc
460
+ required = [:client_id, :client_secret]
461
+ when :api_key
462
+ required = [:api_key]
463
+ when :service_account, :google_service_account
464
+ # Either service_account_key (raw JSON string) or service_account_key_file
465
+ required = [:service_account_key]
466
+ end
467
+
468
+ missing = required.select { |attr| credential[attr].nil? }
469
+ if missing.any?
470
+ puts "ERROR: Missing required attributes: #{missing.join(', ')}"
471
+ else
472
+ puts "Credential appears valid"
473
+ end
474
+
475
+ # Check environment variable resolution
476
+ required.each do |attr|
477
+ value = credential[attr, resolve_env: false]
478
+ if value.is_a?(String) && value.start_with?('ENV:')
479
+ env_var = value.sub(/^ENV:/, '')
480
+ if ENV[env_var].nil?
481
+ puts "WARNING: Environment variable not set: #{env_var}"
482
+ else
483
+ puts "Environment variable resolved: #{env_var}"
484
+ end
485
+ end
486
+ end
487
+ end
488
+
489
+ # Usage
490
+ credential = Legate::Auth::Credential.new(
491
+ auth_type: :oauth2,
492
+ client_id: 'ENV:CLIENT_ID',
493
+ client_secret: 'ENV:CLIENT_SECRET'
494
+ )
495
+
496
+ validate_credential(credential)
497
+ ```
498
+
499
+ ### TokenStore Debugging
500
+
501
+ For debugging token store issues:
502
+
503
+ `TokenStore` does not expose a method to enumerate keys (there is no `all_keys`). Debug a specific token by looking it up by its key:
504
+
505
+ ```ruby
506
+ # Debug a single token by key
507
+ def debug_token(token_store, key)
508
+ token = token_store.get(key)
509
+ if token
510
+ puts "Token type: #{token.auth_type}"
511
+ puts "Expires at: #{token[:expires_at]}"
512
+ puts "Expired?: #{token.expired?}"
513
+ puts "Refreshable: #{token.refreshable? ? 'Yes' : 'No'}" # use refreshable?, not can_refresh?
514
+ else
515
+ puts "Token not found or expired for key: #{key}"
516
+ end
517
+ rescue => e
518
+ puts "Error retrieving token: #{e.message}"
519
+ end
520
+
521
+ # Usage
522
+ token_store = Legate::Auth::TokenStore.new(session_service)
523
+ debug_token(token_store, 'auth_<hash>')
524
+ ```
525
+
526
+ ## When to Contact Support
527
+
528
+ If you've tried all the solutions and still encounter issues:
529
+
530
+ 1. **Check for Library Updates**:
531
+ - Verify you're using the latest version of the Legate Ruby library
532
+ - Check the changelog for fixes related to credential storage
533
+
534
+ 2. **Debug Information to Collect**:
535
+ - Legate Ruby version
536
+ - Ruby version and platform
537
+ - Environment (development, production)
538
+ - Error messages (with sensitive data redacted)
539
+ - Steps to reproduce the issue
540
+
541
+ 3. **Contact Legate Support**:
542
+ - Provide collected debug information
543
+ - Describe your credential storage setup
544
+ - Share reproduction steps
545
+
546
+ ## Next Steps
547
+
548
+ - [Token Lifecycle Management](../guides/token_lifecycle): Advanced token management techniques
549
+ - [OAuth2 Troubleshooting](./oauth2_issues): For OAuth2-specific authentication issues
550
+ - [Environment Variable Management](./environment_variables): Best practices for handling environment variables