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,327 @@
1
+ / File: lib/legate/web/views/auth_credential_detail.slim
2
+ .content.mb-6
3
+ nav.breadcrumb(aria-label="breadcrumbs")
4
+ ul
5
+ li
6
+ a(href="/auth") Authentication
7
+ li
8
+ a(href="/auth/credentials") Credentials
9
+ li.is-active
10
+ a(href="/auth/credentials/#{@credential[:name]}" aria-current="page") = @credential[:name]
11
+
12
+ .level
13
+ .level-left
14
+ .level-item
15
+ div
16
+ h1.title.is-2 = @credential[:name]
17
+ p.subtitle.is-4 = @credential[:description]
18
+ .level-right
19
+ .level-item
20
+ .buttons
21
+ button.button.is-warning#edit-credential-btn
22
+ span.icon
23
+ i.fas.fa-edit
24
+ span Edit
25
+ button.button.is-info#test-credential-btn
26
+ span.icon
27
+ i.fas.fa-vial
28
+ span Test
29
+ button.button.is-danger.is-outlined#delete-credential-btn
30
+ span.icon
31
+ i.fas.fa-trash
32
+ span Delete
33
+
34
+ .columns
35
+ .column.is-half
36
+ .card
37
+ .card-header
38
+ p.card-header-title Credential Information
39
+ .card-content
40
+ .content
41
+ table.table.is-narrow.is-fullwidth
42
+ tbody
43
+ tr
44
+ td <strong>Name:</strong>
45
+ td
46
+ code = @credential[:name]
47
+ tr
48
+ td <strong>Type:</strong>
49
+ td
50
+ span.tag.is-info.is-light = @credential[:auth_type]
51
+ tr
52
+ td <strong>Compatible Schemes:</strong>
53
+ td
54
+ .tags
55
+ - @credential[:compatible_schemes].each do |scheme_name|
56
+ span.tag.is-success.is-light = scheme_name
57
+
58
+ .card.mt-4
59
+ .card-header
60
+ p.card-header-title Current Configuration
61
+ .card-content
62
+ .content
63
+ - if @credential[:current_config].any?
64
+ table.table.is-narrow.is-fullwidth
65
+ tbody
66
+ - @credential[:current_config].each do |key, value|
67
+ tr
68
+ td <strong>#{key.to_s.gsub('_', ' ').split.map(&:capitalize).join(' ')}:</strong>
69
+ td
70
+ - if key.include?('url') || key.include?('uri')
71
+ a(href="#{value}" target="_blank") = value
72
+ - elsif value.to_s.include?('***')
73
+ span.has-text-grey-light = value
74
+ - else
75
+ code = value
76
+ - else
77
+ p.has-text-grey No configuration data available
78
+
79
+ .column.is-half
80
+ .card
81
+ .card-header
82
+ p.card-header-title Usage Information
83
+ .card-content
84
+ .content
85
+ .columns.is-mobile.is-gapless.has-text-centered
86
+ .column
87
+ p.heading Compatible Schemes
88
+ p.title.is-4 = @credential[:compatible_schemes].size
89
+ .column
90
+ p.heading URL Mappings
91
+ p.title.is-4 = @credential[:url_mappings].size
92
+
93
+ - if @credential[:url_mappings].any?
94
+ .card.mt-4
95
+ .card-header
96
+ p.card-header-title URL Mappings
97
+ .card-content
98
+ .content
99
+ .table-container
100
+ table.table.is-fullwidth.is-striped
101
+ thead
102
+ tr
103
+ th Pattern
104
+ th Type
105
+ th Scheme
106
+ tbody
107
+ - @credential[:url_mappings].each do |mapping|
108
+ tr
109
+ td
110
+ code = mapping[:pattern]
111
+ td
112
+ span.tag class=("is-warning" if mapping[:pattern_type] == 'regex')
113
+ = mapping[:pattern_type] == 'regex' ? 'Regex' : 'String'
114
+ td
115
+ span.tag.is-primary.is-light = mapping[:scheme_name]
116
+
117
+ #test-results.card.mt-4.is-hidden
118
+ .card-header
119
+ p.card-header-title Test Results
120
+ .card-content
121
+ .content
122
+ #test-results-content
123
+ /! Test results will be inserted here
124
+
125
+ /! Edit Credential Modal
126
+ #edit-credential-modal.modal
127
+ .modal-background
128
+ .modal-card
129
+ header.modal-card-head
130
+ p.modal-card-title Edit #{@credential[:name]}
131
+ button.delete(aria-label="close")
132
+ section.modal-card-body
133
+ form#edit-credential-form
134
+ - @credential[:config_fields].each do |field|
135
+ .field
136
+ label.label = field[:label]
137
+ .control
138
+ - if field[:type] == 'select'
139
+ .select.is-fullwidth
140
+ select(name="#{field[:name]}" required=field[:required])
141
+ - field[:options].each do |option|
142
+ option(value="#{option}" selected=(@credential[:current_config][field[:name]] == option)) = option
143
+ - elsif field[:type] == 'textarea'
144
+ textarea.textarea(name="#{field[:name]}" placeholder="#{field[:placeholder] || ''}" required=field[:required]) = @credential[:current_config][field[:name]]
145
+ - elsif field[:type] == 'password'
146
+ input.input(type="password" name="#{field[:name]}" placeholder="#{field[:placeholder] || ''}" required=field[:required])
147
+ p.help.is-size-7 Leave blank to keep current value
148
+ - else
149
+ input.input(type="#{field[:type]}" name="#{field[:name]}" value="#{@credential[:current_config][field[:name]]}" placeholder="#{field[:placeholder] || ''}" required=field[:required])
150
+
151
+ footer.modal-card-foot
152
+ button.button.is-primary(type="submit" form="edit-credential-form") Update Credential
153
+ button.button Cancel
154
+
155
+ /! Delete Confirmation Modal
156
+ #delete-credential-modal.modal
157
+ .modal-background
158
+ .modal-card
159
+ header.modal-card-head
160
+ p.modal-card-title Delete Credential
161
+ button.delete(aria-label="close")
162
+ section.modal-card-body
163
+ .content
164
+ p Are you sure you want to delete the credential <strong>#{@credential[:name]}</strong>?
165
+ - if @credential[:url_mappings].any?
166
+ .notification.is-warning
167
+ p <strong>Warning:</strong> This credential is used by #{@credential[:url_mappings].size} URL mapping(s). You must remove these mappings first.
168
+ - else
169
+ p This action cannot be undone.
170
+
171
+ footer.modal-card-foot
172
+ button.button.is-danger#confirm-delete-btn Delete Credential
173
+ button.button Cancel
174
+
175
+ javascript:
176
+ document.addEventListener('DOMContentLoaded', function() {
177
+ const editCredentialBtn = document.getElementById('edit-credential-btn');
178
+ const editCredentialModal = document.getElementById('edit-credential-modal');
179
+ const editCredentialForm = document.getElementById('edit-credential-form');
180
+ const testCredentialBtn = document.getElementById('test-credential-btn');
181
+ const testResults = document.getElementById('test-results');
182
+ const testResultsContent = document.getElementById('test-results-content');
183
+ const deleteCredentialBtn = document.getElementById('delete-credential-btn');
184
+ const deleteCredentialModal = document.getElementById('delete-credential-modal');
185
+ const confirmDeleteBtn = document.getElementById('confirm-delete-btn');
186
+
187
+ // Show edit modal
188
+ editCredentialBtn.addEventListener('click', function() {
189
+ editCredentialModal.classList.add('is-active');
190
+ });
191
+
192
+ // Show delete modal
193
+ deleteCredentialBtn.addEventListener('click', function() {
194
+ deleteCredentialModal.classList.add('is-active');
195
+ });
196
+
197
+ // Hide modals
198
+ function hideModals() {
199
+ editCredentialModal.classList.remove('is-active');
200
+ deleteCredentialModal.classList.remove('is-active');
201
+ }
202
+
203
+ document.querySelectorAll('.modal-background, .delete, .button:not(.is-primary):not(.is-danger)').forEach(function(element) {
204
+ element.addEventListener('click', hideModals);
205
+ });
206
+
207
+ // Handle edit form submission
208
+ editCredentialForm.addEventListener('submit', function(e) {
209
+ e.preventDefault();
210
+
211
+ const formData = new FormData(this);
212
+
213
+ fetch(`/auth/credentials/#{@credential[:name]}`, {
214
+ method: 'PUT',
215
+ body: formData
216
+ })
217
+ .then(response => response.json())
218
+ .then(data => {
219
+ if (data.success) {
220
+ hideModals();
221
+ if (typeof showToast === 'function') {
222
+ showToast(data.message, 'is-success');
223
+ }
224
+ // Reload the page to show updated configuration
225
+ window.location.reload();
226
+ } else {
227
+ if (typeof showToast === 'function') {
228
+ showToast(data.error || 'Failed to update credential', 'is-danger');
229
+ }
230
+ }
231
+ })
232
+ .catch(error => {
233
+ console.error('Error:', error);
234
+ if (typeof showToast === 'function') {
235
+ showToast('Network error occurred', 'is-danger');
236
+ }
237
+ });
238
+ });
239
+
240
+ // Handle test credential
241
+ testCredentialBtn.addEventListener('click', function() {
242
+ testCredentialBtn.classList.add('is-loading');
243
+ testResults.classList.add('is-hidden');
244
+
245
+ Legate.apiRequest(`/auth/credentials/#{@credential[:name]}/test`, {
246
+ method: 'POST'
247
+ })
248
+ .then(data => {
249
+ testCredentialBtn.classList.remove('is-loading');
250
+
251
+ let resultsHTML = '';
252
+ if (data.tests && data.tests.length > 0) {
253
+ resultsHTML += '<div class="content">';
254
+ data.tests.forEach(function(test) {
255
+ const statusClass = test.status === 'passed' ? 'is-success' : 'is-danger';
256
+ const icon = test.status === 'passed' ? 'fa-check' : 'fa-times';
257
+ resultsHTML += `
258
+ <div class="notification ${statusClass} is-light">
259
+ <span class="icon-text">
260
+ <span class="icon">
261
+ <i class="fas ${icon}"></i>
262
+ </span>
263
+ <span><strong>${escapeHtml(test.name)}:</strong> ${escapeHtml(test.message)}</span>
264
+ </span>
265
+ </div>
266
+ `;
267
+ });
268
+ resultsHTML += '</div>';
269
+
270
+ const overallClass = data.success ? 'is-success' : 'is-danger';
271
+ const overallIcon = data.success ? 'fa-check-circle' : 'fa-exclamation-triangle';
272
+ const overallMessage = data.success ? 'All tests passed' : 'Some tests failed';
273
+
274
+ resultsHTML = `
275
+ <div class="notification ${overallClass}">
276
+ <span class="icon-text">
277
+ <span class="icon">
278
+ <i class="fas ${overallIcon}"></i>
279
+ </span>
280
+ <span><strong>${overallMessage}</strong></span>
281
+ </span>
282
+ </div>
283
+ ` + resultsHTML;
284
+ } else {
285
+ resultsHTML = '<div class="notification is-info">No test results available</div>';
286
+ }
287
+
288
+ testResultsContent.innerHTML = resultsHTML;
289
+ testResults.classList.remove('is-hidden');
290
+ })
291
+ .catch(error => {
292
+ testCredentialBtn.classList.remove('is-loading');
293
+ console.error('Error:', error);
294
+ Legate.renderError(testResultsContent, 'Error running tests: ' + error.message);
295
+ testResults.classList.remove('is-hidden');
296
+ });
297
+ });
298
+
299
+ // Handle delete confirmation
300
+ confirmDeleteBtn.addEventListener('click', function() {
301
+ fetch(`/auth/credentials/#{@credential[:name]}`, {
302
+ method: 'DELETE'
303
+ })
304
+ .then(response => response.json())
305
+ .then(data => {
306
+ if (data.success) {
307
+ if (typeof showToast === 'function') {
308
+ showToast(data.message, 'is-success');
309
+ }
310
+ // Redirect to credentials list
311
+ window.location.href = '/auth/credentials';
312
+ } else {
313
+ hideModals();
314
+ if (typeof showToast === 'function') {
315
+ showToast(data.error || 'Failed to delete credential', 'is-danger');
316
+ }
317
+ }
318
+ })
319
+ .catch(error => {
320
+ console.error('Error:', error);
321
+ hideModals();
322
+ if (typeof showToast === 'function') {
323
+ showToast('Network error occurred', 'is-danger');
324
+ }
325
+ });
326
+ });
327
+ });
@@ -0,0 +1,261 @@
1
+ / File: lib/legate/web/views/auth_credentials.slim
2
+ .content.mb-6
3
+ nav.breadcrumb(aria-label="breadcrumbs")
4
+ ul
5
+ li
6
+ a(href="/auth") Authentication
7
+ li.is-active
8
+ a(href="/auth/credentials" aria-current="page") Credentials
9
+
10
+ h1.title.is-2 Authentication Credentials
11
+ p.subtitle.is-4 Manage authentication credentials for external services
12
+
13
+ .buttons.mb-4
14
+ button.button.is-primary#add-credential-btn
15
+ span.icon
16
+ i.fas.fa-plus
17
+ span Add New Credential
18
+
19
+ - if @credentials && @credentials.any?
20
+ .columns.is-multiline
21
+ - @credentials.each do |credential|
22
+ .column.is-half
23
+ .card
24
+ .card-content
25
+ .media
26
+ .media-left
27
+ span.icon.is-large.has-text-info
28
+ - case credential[:auth_type]
29
+ - when :api_key
30
+ i.fas.fa-key.fa-2x
31
+ - when :oauth2, :oidc
32
+ i.fas.fa-shield-alt.fa-2x
33
+ - when :service_account, :google_service_account
34
+ i.fas.fa-robot.fa-2x
35
+ - when :http_bearer
36
+ i.fas.fa-ticket-alt.fa-2x
37
+ - else
38
+ i.fas.fa-id-card.fa-2x
39
+ .media-content
40
+ p.title.is-5 = credential[:name]
41
+ p.subtitle.is-6 = credential[:description]
42
+ .content
43
+ p.is-size-7 = credential[:masked_info]
44
+ .level.is-mobile.mt-3
45
+ .level-left
46
+ .level-item
47
+ .tags
48
+ span.tag.is-info.is-light = credential[:auth_type]
49
+ .level-right
50
+ .level-item
51
+ .buttons.are-small
52
+ a.button.is-primary.is-outlined(href="/auth/credentials/#{credential[:name]}")
53
+ span.icon.is-small
54
+ i.fas.fa-eye
55
+ span Details
56
+
57
+ .content.is-small.mt-3
58
+ .columns.is-mobile.is-gapless
59
+ .column
60
+ .has-text-centered
61
+ p.heading Compatible Schemes
62
+ p.title.is-6 = credential[:compatible_schemes_count]
63
+ .column
64
+ .has-text-centered
65
+ p.heading URL Mappings
66
+ p.title.is-6 = credential[:url_mappings_count]
67
+
68
+ - else
69
+ .columns.is-centered
70
+ .column.is-half
71
+ .notification.is-info
72
+ h3.title.is-4 No Credentials Configured
73
+ p No authentication credentials are currently configured.
74
+ p Add credentials to enable agents to authenticate with external services.
75
+
76
+ .content.mt-6
77
+ h2.title.is-4 Credential Security
78
+ .columns
79
+ .column.is-half
80
+ .content
81
+ h3.title.is-5
82
+ span.icon.has-text-success
83
+ i.fas.fa-shield-alt
84
+ span Secure Storage
85
+ p All sensitive credential data is securely stored and encrypted.
86
+ p Only masked versions are shown in the web interface for security.
87
+
88
+ .column.is-half
89
+ .content
90
+ h3.title.is-5
91
+ span.icon.has-text-warning
92
+ i.fas.fa-exclamation-triangle
93
+ span Important Notes
94
+ p Never share or expose full credential values.
95
+ p Credentials are automatically used by agents when making authenticated requests.
96
+ p Test credentials regularly to ensure they remain valid.
97
+
98
+ /! Add New Credential Modal
99
+ #add-credential-modal.modal
100
+ .modal-background
101
+ .modal-card
102
+ header.modal-card-head
103
+ p.modal-card-title Add New Authentication Credential
104
+ button.delete(aria-label="close")
105
+ section.modal-card-body
106
+ form#add-credential-form
107
+ .field
108
+ label.label Credential Type
109
+ .control
110
+ .select.is-fullwidth
111
+ select#credential-type-select(name="auth_type" required)
112
+ option(value="") Select credential type...
113
+ option(value="api_key") API Key
114
+ option(value="http_bearer") HTTP Bearer
115
+ option(value="oauth2") OAuth2
116
+ option(value="oidc") OpenID Connect
117
+ option(value="service_account") Service Account
118
+ option(value="google_service_account") Google Service Account
119
+ option(value="basic") Basic Auth
120
+
121
+ .field
122
+ label.label Credential Name
123
+ .control
124
+ input.input(type="text" name="credential_name" placeholder="Enter unique credential name" required)
125
+ p.help Give this credential a unique name (e.g., "github_oauth", "api_key_prod")
126
+
127
+ #credential-config-fields
128
+ /! Dynamic configuration fields will be inserted here
129
+
130
+ footer.modal-card-foot
131
+ button.button.is-primary(type="submit" form="add-credential-form") Add Credential
132
+ button.button Cancel
133
+
134
+ javascript:
135
+ document.addEventListener('DOMContentLoaded', function() {
136
+ const addCredentialBtn = document.getElementById('add-credential-btn');
137
+ const addCredentialModal = document.getElementById('add-credential-modal');
138
+ const credentialTypeSelect = document.getElementById('credential-type-select');
139
+ const credentialConfigFields = document.getElementById('credential-config-fields');
140
+ const addCredentialForm = document.getElementById('add-credential-form');
141
+
142
+ // Credential configuration templates
143
+ const credentialConfigs = {
144
+ api_key: [
145
+ { name: 'api_key', type: 'password', required: true, label: 'API Key', placeholder: 'Enter your API key' },
146
+ { name: 'location', type: 'select', required: false, label: 'Location', options: ['header', 'query', 'cookie'], default: 'header' },
147
+ { name: 'name', type: 'text', required: false, label: 'Parameter Name', placeholder: 'X-API-Key' }
148
+ ],
149
+ http_bearer: [
150
+ { name: 'bearer_token', type: 'password', required: true, label: 'Bearer Token', placeholder: 'Enter bearer token' }
151
+ ],
152
+ oauth2: [
153
+ { name: 'client_id', type: 'text', required: true, label: 'Client ID', placeholder: 'Enter client ID' },
154
+ { name: 'client_secret', type: 'password', required: true, label: 'Client Secret', placeholder: 'Enter client secret' },
155
+ { name: 'redirect_uri', type: 'url', required: false, label: 'Redirect URI', placeholder: 'https://your-app.com/callback' },
156
+ { name: 'scopes', type: 'text', required: false, label: 'Scopes (space-separated)', placeholder: 'read write' }
157
+ ],
158
+ oidc: [
159
+ { name: 'client_id', type: 'text', required: true, label: 'Client ID', placeholder: 'Enter client ID' },
160
+ { name: 'client_secret', type: 'password', required: true, label: 'Client Secret', placeholder: 'Enter client secret' },
161
+ { name: 'redirect_uri', type: 'url', required: false, label: 'Redirect URI', placeholder: 'https://your-app.com/callback' },
162
+ { name: 'scopes', type: 'text', required: false, label: 'Scopes (space-separated)', placeholder: 'openid profile email' }
163
+ ],
164
+ service_account: [
165
+ { name: 'client_email', type: 'email', required: true, label: 'Client Email', placeholder: 'service-account@project.iam.gserviceaccount.com' },
166
+ { name: 'private_key', type: 'textarea', required: true, label: 'Private Key', placeholder: '-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----' },
167
+ { name: 'project_id', type: 'text', required: false, label: 'Project ID', placeholder: 'your-project-id' }
168
+ ],
169
+ google_service_account: [
170
+ { name: 'service_account_key', type: 'textarea', required: true, label: 'Service Account Key (JSON)', placeholder: '{"type": "service_account", "project_id": "..."}' }
171
+ ],
172
+ basic: [
173
+ { name: 'username', type: 'text', required: true, label: 'Username', placeholder: 'Enter username' },
174
+ { name: 'password', type: 'password', required: true, label: 'Password', placeholder: 'Enter password' }
175
+ ]
176
+ };
177
+
178
+ // Show modal
179
+ addCredentialBtn.addEventListener('click', function() {
180
+ addCredentialModal.classList.add('is-active');
181
+ });
182
+
183
+ // Hide modal
184
+ function hideModal() {
185
+ addCredentialModal.classList.remove('is-active');
186
+ addCredentialForm.reset();
187
+ credentialConfigFields.innerHTML = '';
188
+ }
189
+
190
+ addCredentialModal.querySelectorAll('.modal-background, .delete, .button:not(.is-primary)').forEach(function(element) {
191
+ element.addEventListener('click', hideModal);
192
+ });
193
+
194
+ // Update configuration fields when credential type changes
195
+ credentialTypeSelect.addEventListener('change', function() {
196
+ const credentialType = this.value;
197
+ credentialConfigFields.innerHTML = '';
198
+
199
+ if (credentialConfigs[credentialType]) {
200
+ credentialConfigs[credentialType].forEach(function(field) {
201
+ const fieldDiv = document.createElement('div');
202
+ fieldDiv.className = 'field';
203
+
204
+ let fieldHTML = `<label class="label">${field.label}</label><div class="control">`;
205
+
206
+ if (field.type === 'select') {
207
+ fieldHTML += `<div class="select is-fullwidth"><select name="${field.name}" ${field.required ? 'required' : ''}>`;
208
+ if (field.options) {
209
+ field.options.forEach(function(option) {
210
+ const selected = field.default === option ? 'selected' : '';
211
+ fieldHTML += `<option value="${option}" ${selected}>${option}</option>`;
212
+ });
213
+ }
214
+ fieldHTML += '</select></div>';
215
+ } else if (field.type === 'textarea') {
216
+ fieldHTML += `<textarea class="textarea" name="${field.name}" placeholder="${field.placeholder || ''}" ${field.required ? 'required' : ''}></textarea>`;
217
+ } else {
218
+ fieldHTML += `<input class="input" type="${field.type}" name="${field.name}"
219
+ placeholder="${field.placeholder || ''}" ${field.required ? 'required' : ''}>`;
220
+ }
221
+
222
+ fieldHTML += '</div>';
223
+ fieldDiv.innerHTML = fieldHTML;
224
+ credentialConfigFields.appendChild(fieldDiv);
225
+ });
226
+ }
227
+ });
228
+
229
+ // Handle form submission
230
+ addCredentialForm.addEventListener('submit', function(e) {
231
+ e.preventDefault();
232
+
233
+ const formData = new FormData(this);
234
+
235
+ fetch('/auth/credentials', {
236
+ method: 'POST',
237
+ body: formData
238
+ })
239
+ .then(response => response.json())
240
+ .then(data => {
241
+ if (data.success) {
242
+ hideModal();
243
+ if (typeof showToast === 'function') {
244
+ showToast(data.message, 'is-success');
245
+ }
246
+ // Reload the page to show the new credential
247
+ window.location.reload();
248
+ } else {
249
+ if (typeof showToast === 'function') {
250
+ showToast(data.error || 'Failed to add credential', 'is-danger');
251
+ }
252
+ }
253
+ })
254
+ .catch(error => {
255
+ console.error('Error:', error);
256
+ if (typeof showToast === 'function') {
257
+ showToast('Network error occurred', 'is-danger');
258
+ }
259
+ });
260
+ });
261
+ });
@@ -0,0 +1,94 @@
1
+ / File: lib/legate/web/views/auth_debug.slim
2
+ .content.mb-6
3
+ nav.breadcrumb(aria-label="breadcrumbs")
4
+ ul
5
+ li
6
+ a(href="/auth") Authentication
7
+ li.is-active
8
+ a(href="/auth/debug" aria-current="page") Debug
9
+
10
+ h1.title.is-2 Authentication Debug Information
11
+ p.subtitle.is-4 Detailed information about the authentication manager state
12
+
13
+ - if @debug_info
14
+ .columns
15
+ .column.is-half
16
+ .card
17
+ .card-header
18
+ p.card-header-title Authentication Manager
19
+ .card-content
20
+ .content
21
+ table.table.is-narrow
22
+ tbody
23
+ tr
24
+ td <strong>Class:</strong>
25
+ td
26
+ code = @debug_info[:manager_class]
27
+ tr
28
+ td <strong>Instance ID:</strong>
29
+ td
30
+ code = @debug_info[:manager_instance_id]
31
+ tr
32
+ td <strong>Schemes Registered:</strong>
33
+ td = @debug_info[:schemes_registered].size
34
+ tr
35
+ td <strong>Credentials Registered:</strong>
36
+ td = @debug_info[:credentials_registered].size
37
+ tr
38
+ td <strong>URL Mappings:</strong>
39
+ td = @debug_info[:url_mappings_count]
40
+
41
+ .column.is-half
42
+ .card
43
+ .card-header
44
+ p.card-header-title Registered Components
45
+ .card-content
46
+ .content
47
+ h4.title.is-6 Schemes
48
+ - if @debug_info[:schemes_registered].any?
49
+ .tags
50
+ - @debug_info[:schemes_registered].each do |scheme_name|
51
+ span.tag.is-primary.is-light = scheme_name
52
+ - else
53
+ p.has-text-grey No schemes registered
54
+
55
+ h4.title.is-6.mt-4 Credentials
56
+ - if @debug_info[:credentials_registered].any?
57
+ .tags
58
+ - @debug_info[:credentials_registered].each do |credential_name|
59
+ span.tag.is-info.is-light = credential_name
60
+ - else
61
+ p.has-text-grey No credentials registered
62
+
63
+ - else
64
+ .columns.is-centered
65
+ .column.is-half
66
+ .notification.is-danger
67
+ h3.title.is-4 Debug Information Unavailable
68
+ p Could not retrieve debug information from the authentication manager.
69
+
70
+ .content.mt-6
71
+ h2.title.is-4 Troubleshooting
72
+ .columns
73
+ .column.is-half
74
+ .content
75
+ h3.title.is-5
76
+ span.icon.has-text-warning
77
+ i.fas.fa-exclamation-triangle
78
+ span Common Issues
79
+ ul
80
+ li <strong>No schemes registered:</strong> Authentication system may not be properly initialized
81
+ li <strong>No credentials:</strong> Add credentials for the services your agents will use
82
+ li <strong>Manager unavailable:</strong> Check that the authentication system dependencies are loaded
83
+
84
+ .column.is-half
85
+ .content
86
+ h3.title.is-5
87
+ span.icon.has-text-info
88
+ i.fas.fa-lightbulb
89
+ span Expected State
90
+ p In a properly configured system, you should see:
91
+ ul
92
+ li Default schemes (api_key, http_bearer, oauth2, oidc, service_account, google_service_account)
93
+ li At least one credential for each service your agents use
94
+ li URL mappings for automatic authentication