databricks-tellr-app 0.4.3.dev11__tar.gz → 0.4.3.dev13__tar.gz

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 (167) hide show
  1. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/PKG-INFO +1 -1
  2. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/databricks_tellr_app.egg-info/PKG-INFO +1 -1
  3. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/pyproject.toml +1 -1
  4. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/main.py +11 -5
  5. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/middleware/security_headers.py +22 -0
  6. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/chat.py +2 -14
  7. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/export.py +4 -4
  8. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/google_slides.py +100 -51
  9. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/sessions.py +4 -84
  10. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/settings/identities.py +3 -3
  11. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/setup.py +2 -2
  12. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/slides.py +13 -13
  13. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/verification.py +3 -3
  14. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/encryption.py +54 -32
  15. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/encryption_key.py +6 -2
  16. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/agent.py +17 -4
  17. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/README.md +0 -0
  18. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/databricks_tellr_app/__init__.py +0 -0
  19. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/databricks_tellr_app/run.py +0 -0
  20. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/databricks_tellr_app.egg-info/SOURCES.txt +0 -0
  21. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/databricks_tellr_app.egg-info/dependency_links.txt +0 -0
  22. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/databricks_tellr_app.egg-info/requires.txt +0 -0
  23. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/databricks_tellr_app.egg-info/top_level.txt +0 -0
  24. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/setup.cfg +0 -0
  25. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/setup.py +0 -0
  26. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/__init__.py +0 -0
  27. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/__init__.py +0 -0
  28. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/_otel_bootstrap.py +0 -0
  29. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/fixtures/tour_demo_deck.json +0 -0
  30. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/mcp_auth.py +0 -0
  31. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/mcp_server.py +0 -0
  32. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/middleware/__init__.py +0 -0
  33. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/middleware/csrf.py +0 -0
  34. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/middleware/request_logging.py +0 -0
  35. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/__init__.py +0 -0
  36. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/_authz.py +0 -0
  37. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/admin.py +0 -0
  38. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/admin_usage.py +0 -0
  39. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/agent_config.py +0 -0
  40. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/deck_contributors.py +0 -0
  41. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/feedback.py +0 -0
  42. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/images.py +0 -0
  43. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/local_version.py +0 -0
  44. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/profiles.py +0 -0
  45. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/settings/__init__.py +0 -0
  46. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/settings/contributors.py +0 -0
  47. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/settings/deck_prompts.py +0 -0
  48. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/settings/design_systems.py +0 -0
  49. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/settings/slide_styles.py +0 -0
  50. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/tools.py +0 -0
  51. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/tour.py +0 -0
  52. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/routes/version.py +0 -0
  53. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/__init__.py +0 -0
  54. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/agent_config.py +0 -0
  55. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/feedback.py +0 -0
  56. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/requests.py +0 -0
  57. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/responses.py +0 -0
  58. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/settings/__init__.py +0 -0
  59. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/settings/requests.py +0 -0
  60. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/settings/responses.py +0 -0
  61. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/schemas/streaming.py +0 -0
  62. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/__init__.py +0 -0
  63. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/chat_service.py +0 -0
  64. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/export_job_queue.py +0 -0
  65. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/feedback_service.py +0 -0
  66. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/job_queue.py +0 -0
  67. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/session_manager.py +0 -0
  68. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/session_naming.py +0 -0
  69. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/usage_events.py +0 -0
  70. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/services/usage_service.py +0 -0
  71. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/utils/__init__.py +0 -0
  72. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/api/utils/validation.py +0 -0
  73. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/__init__.py +0 -0
  74. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/config_loader.py +0 -0
  75. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/context_utils.py +0 -0
  76. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/database.py +0 -0
  77. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/databricks_client.py +0 -0
  78. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/defaults.py +0 -0
  79. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/init_default_profile.py +0 -0
  80. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/lakebase.py +0 -0
  81. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/migrate_profiles_to_agent_config.py +0 -0
  82. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/mlflow_agent_spans.py +0 -0
  83. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/mlflow_tracing.py +0 -0
  84. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/otel_logging.py +0 -0
  85. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/permission_context.py +0 -0
  86. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/prompt_modules.py +0 -0
  87. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/settings_db.py +0 -0
  88. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/core/user_context.py +0 -0
  89. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/__init__.py +0 -0
  90. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/__init__.py +0 -0
  91. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/deck_contributor.py +0 -0
  92. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/design_system.py +0 -0
  93. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/feedback.py +0 -0
  94. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/genie_space.py +0 -0
  95. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/google_global_credentials.py +0 -0
  96. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/google_oauth_token.py +0 -0
  97. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/identity.py +0 -0
  98. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/image.py +0 -0
  99. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/profile.py +0 -0
  100. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/profile_contributor.py +0 -0
  101. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/prompts.py +0 -0
  102. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/request_log.py +0 -0
  103. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/session.py +0 -0
  104. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/slide_deck_prompt.py +0 -0
  105. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/slide_style_library.py +0 -0
  106. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/usage_event.py +0 -0
  107. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/models/user_preference.py +0 -0
  108. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/database/types.py +0 -0
  109. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/domain/__init__.py +0 -0
  110. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/domain/slide.py +0 -0
  111. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/domain/slide_deck.py +0 -0
  112. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/__init__.py +0 -0
  113. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/agent_factory.py +0 -0
  114. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/config_service.py +0 -0
  115. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/config_validator.py +0 -0
  116. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/converter_jail/__init__.py +0 -0
  117. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/converter_jail/ast_guard.py +0 -0
  118. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/converter_jail/codeprep.py +0 -0
  119. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/converter_jail/gslides_runner.py +0 -0
  120. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/converter_jail/jail.py +0 -0
  121. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/converter_jail/pptx_runner.py +0 -0
  122. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/converter_jail/protocol.py +0 -0
  123. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/design_system_compiler.py +0 -0
  124. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/design_system_service.py +0 -0
  125. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/design_system_templates.py +0 -0
  126. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/drive_uploader.py +0 -0
  127. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/evaluation/__init__.py +0 -0
  128. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/evaluation/llm_judge.py +0 -0
  129. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/genie_service.py +0 -0
  130. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/google_slides_auth.py +0 -0
  131. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/google_slides_prompts_defaults.py +0 -0
  132. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/html_to_google_slides.py +0 -0
  133. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/html_to_pptx.py +0 -0
  134. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/identity_provider.py +0 -0
  135. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/identity_providers/__init__.py +0 -0
  136. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/identity_providers/account_provider.py +0 -0
  137. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/identity_providers/local_provider.py +0 -0
  138. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/identity_providers/workspace_provider.py +0 -0
  139. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/image_service.py +0 -0
  140. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/image_tools.py +0 -0
  141. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/permission_service.py +0 -0
  142. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/pptx_from_html_huashu.py +0 -0
  143. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/pptx_from_records.py +0 -0
  144. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/pptx_prompts_defaults.py +0 -0
  145. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/profile_service.py +0 -0
  146. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/streaming_callback.py +0 -0
  147. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/tools/__init__.py +0 -0
  148. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/tools/agent_bricks_tool.py +0 -0
  149. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/tools/ds_asset_tool.py +0 -0
  150. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/tools/genie_tool.py +0 -0
  151. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/tools/mcp_tool.py +0 -0
  152. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/tools/model_endpoint_tool.py +0 -0
  153. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/tools/vector_tool.py +0 -0
  154. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/services/validator.py +0 -0
  155. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/__init__.py +0 -0
  156. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/css_utils.py +0 -0
  157. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/ds_asset_utils.py +0 -0
  158. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/error_handling.py +0 -0
  159. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/html_safety.py +0 -0
  160. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/html_utils.py +0 -0
  161. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/image_utils.py +0 -0
  162. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/js_validator.py +0 -0
  163. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/logging_config.py +0 -0
  164. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/pi_filter.py +0 -0
  165. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/slide_hash.py +0 -0
  166. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/spotlight.py +0 -0
  167. {databricks_tellr_app-0.4.3.dev11 → databricks_tellr_app-0.4.3.dev13}/src/utils/text_caps.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: databricks-tellr-app
3
- Version: 0.4.3.dev11
3
+ Version: 0.4.3.dev13
4
4
  Summary: Tellr application package for Databricks Apps
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: databricks-tellr-app
3
- Version: 0.4.3.dev11
3
+ Version: 0.4.3.dev13
4
4
  Summary: Tellr application package for Databricks Apps
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "databricks-tellr-app"
7
- version = "0.4.3.dev11"
7
+ version = "0.4.3.dev13"
8
8
  description = "Tellr application package for Databricks Apps"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -321,14 +321,12 @@ async def user_auth_middleware(request: Request, call_next):
321
321
  user_name = None
322
322
 
323
323
  if token:
324
- # Diagnostic logging: check if token is service principal ID (debug to avoid log spam on every request/poll)
325
- token_prefix = token[:20] if len(token) > 20 else token
324
+ # Diagnostic logging: flag SP-vs-user tokens. F-CR-9 (SDR-4437): never log
325
+ # any part of the bearer token (no prefix, no length) — only derived booleans.
326
326
  is_sp_token = client_id and token.startswith(client_id)
327
327
  logger.debug(
328
328
  "OBO auth: extracted token from header",
329
329
  extra={
330
- "token_prefix": token_prefix,
331
- "token_length": len(token),
332
330
  "is_service_principal": is_sp_token,
333
331
  "header_present": True,
334
332
  },
@@ -491,11 +489,19 @@ logger.info("MCP server mounted at /mcp")
491
489
 
492
490
  @app.get("/api/health")
493
491
  async def health():
494
- """Health check endpoint."""
492
+ """Health check endpoint.
493
+
494
+ ``encryption_key_source`` is load-bearing for deployment: ``tellr.update``
495
+ polls it to confirm a relocated app is reading the secret before it deletes
496
+ the Lakebase key row. Reports the source only — never the key.
497
+ """
498
+ from src.core.encryption import key_source
499
+
495
500
  return {
496
501
  "status": "healthy",
497
502
  "environment": ENVIRONMENT,
498
503
  "version": "0.3.0",
504
+ "encryption_key_source": key_source(),
499
505
  }
500
506
 
501
507
 
@@ -31,6 +31,28 @@ Content-Security-Policy differentiated by response type:
31
31
  'none', no eval) plus the html_safety.py scanner, and any header at
32
32
  all is a strict improvement over the previous no-CSP state.
33
33
 
34
+ SDR-4437 M-CSP — ACCEPTED RESIDUAL (pending SE sign-off). M-CSP asks
35
+ to move ``script-src`` off ``'unsafe-inline'`` to hashes/nonces. That
36
+ is infeasible here and was verified:
37
+ * The SPA's own document has NO inline <script> — index.html loads a
38
+ single external module (``/src/main.tsx``), already covered by
39
+ ``'self'``. So the SPA itself does not need 'unsafe-inline'.
40
+ * The 'unsafe-inline' exists ONLY for the srcdoc slide iframes, whose
41
+ generated HTML contains arbitrary inline <script> (Chart.js init,
42
+ etc.) and which inherit THIS document policy in addition to their
43
+ own SLIDE_CSP meta (both enforce; most restrictive wins).
44
+ * Per CSP2+, adding any nonce or hash to ``script-src`` makes the
45
+ browser IGNORE 'unsafe-inline'. A nonce on the parent would
46
+ therefore disable inline execution for the inherited srcdoc slide
47
+ scripts and break slide rendering app-wide — you cannot have
48
+ "nonce + unsafe-inline" both take effect.
49
+ Removing it would require re-architecting slides away from srcdoc
50
+ (backend-served ``src`` iframes), which the frame-ancestors / no-src
51
+ design above deliberately avoids. The residual is bounded: slides stay
52
+ confined by SLIDE_CSP (an egress boundary) + the html_safety scanner,
53
+ and the DOCUMENT_CSP ⊇ SLIDE_CSP superset invariant is locked by
54
+ tests/unit/test_export_csp.py::test_document_csp_header_is_superset_of_slide_csp.
55
+
34
56
  - Everything else (JSON APIs, assets, SSE) gets the deny-all
35
57
  ``API_CSP`` — nothing executes in a JSON response.
36
58
 
@@ -384,7 +384,7 @@ async def send_message(
384
384
  logger.error(f"Chat request failed: {e}", exc_info=True)
385
385
  raise HTTPException(
386
386
  status_code=500,
387
- detail=f"Failed to process message: {str(e)}",
387
+ detail="Failed to process message",
388
388
  ) from e
389
389
  finally:
390
390
  await asyncio.to_thread(
@@ -543,18 +543,6 @@ async def send_message_streaming(
543
543
  )
544
544
 
545
545
 
546
- @router.get("/health")
547
- async def health_check():
548
- """Health check endpoint.
549
-
550
- Returns:
551
- Status information
552
- """
553
- return {
554
- "status": "healthy",
555
- "service": "AI Slide Generator",
556
- }
557
-
558
546
 
559
547
  @router.post("/chat/async")
560
548
  async def submit_chat_async(
@@ -662,7 +650,7 @@ async def submit_chat_async(
662
650
  session_manager.release_session_lock, request.session_id
663
651
  )
664
652
  logger.error(f"Failed to submit async chat: {e}")
665
- raise HTTPException(status_code=500, detail=str(e))
653
+ raise HTTPException(status_code=500, detail="Internal server error")
666
654
 
667
655
 
668
656
  @router.get("/chat/poll/{request_id}")
@@ -754,13 +754,13 @@ async def export_to_pptx(request: ExportPPTXRequest):
754
754
  temp_dir.rmdir()
755
755
  except Exception:
756
756
  pass
757
- raise HTTPException(status_code=500, detail=f"Export failed: {str(e)}")
757
+ raise HTTPException(status_code=500, detail="Export failed")
758
758
 
759
759
  except HTTPException:
760
760
  raise
761
761
  except Exception as e:
762
762
  logger.error("PPTX export failed", exc_info=True, extra={"error": str(e)})
763
- raise HTTPException(status_code=500, detail=f"Export failed: {str(e)}")
763
+ raise HTTPException(status_code=500, detail="Export failed")
764
764
 
765
765
 
766
766
  # =============================================================================
@@ -893,7 +893,7 @@ async def start_pptx_export_async(request: ExportPPTXRequest):
893
893
  except Exception as e:
894
894
  total_time = time.time() - start_time
895
895
  logger.error(f"Failed to start async export after {total_time:.2f}s: {e}", exc_info=True)
896
- raise HTTPException(status_code=500, detail=str(e))
896
+ raise HTTPException(status_code=500, detail="Failed to start export")
897
897
 
898
898
 
899
899
  @router.get("/pptx/poll/{job_id}", response_model=ExportJobResponse)
@@ -1038,7 +1038,7 @@ async def export_pptx_editable_from_records(request: ExportPPTXFromRecordsReques
1038
1038
  pptx_bytes = build_pptx(title, request.slides, font_mode=font_mode)
1039
1039
  except Exception as e:
1040
1040
  logger.exception(f"Editable PPTX emission failed: {e}")
1041
- raise HTTPException(status_code=500, detail=str(e))
1041
+ raise HTTPException(status_code=500, detail="Editable PPTX export failed")
1042
1042
 
1043
1043
  safe = "".join(c if c.isalnum() or c in "-_" else "_" for c in title).strip("_") or "slides"
1044
1044
  from fastapi.responses import Response
@@ -10,9 +10,10 @@ user tokens are stored per-user in the ``google_oauth_tokens`` table.
10
10
  import json
11
11
  import logging
12
12
  import os
13
+ import secrets
13
14
  from typing import Any, Optional
14
15
 
15
- from fastapi import APIRouter, Depends, HTTPException, Query, Request
16
+ from fastapi import APIRouter, Depends, HTTPException, Query, Request, Response
16
17
  from fastapi.responses import HTMLResponse
17
18
  from pydantic import BaseModel
18
19
  from sqlalchemy.orm import Session
@@ -33,6 +34,12 @@ logger = logging.getLogger(__name__)
33
34
 
34
35
  router = APIRouter(prefix="/api/export/google-slides", tags=["google-slides"])
35
36
 
37
+ # F-CR-3 (SDR-4437): the OAuth "state" carries an unguessable nonce that is also
38
+ # stored in this short-lived cookie; the callback requires them to match before
39
+ # exchanging the authorization code (anti-CSRF / anti-login-CSRF double-submit).
40
+ _OAUTH_STATE_COOKIE = "g_oauth_state"
41
+ _OAUTH_COOKIE_PATH = "/api/export/google-slides"
42
+
36
43
 
37
44
  # -------------------------------------------------------------------------
38
45
  # Helpers
@@ -98,32 +105,76 @@ class AuthUrlResponse(BaseModel):
98
105
  # -------------------------------------------------------------------------
99
106
 
100
107
 
101
- def _build_redirect_uri(request: Request) -> str:
102
- """Build the OAuth callback redirect URI from the current request.
103
-
104
- Google requires redirect URIs to match *exactly* what's registered in GCP,
105
- with no query parameters.
108
+ def _build_app_origin(request: Request) -> str:
109
+ """Return the public origin (``scheme://host``) serving the app.
106
110
 
107
111
  Behind a reverse proxy (e.g. Databricks Apps), ``request.base_url``
108
112
  returns the internal address (``http://localhost:8000``). We use the
109
113
  ``X-Forwarded-Host`` / ``X-Forwarded-Proto`` headers set by the proxy
110
- to reconstruct the public URL instead.
111
-
112
- For localhost, Google only allows ``http``.
114
+ to reconstruct the public URL instead. For localhost, force ``http``.
113
115
  """
114
116
  forwarded_host = request.headers.get("x-forwarded-host")
115
117
  forwarded_proto = request.headers.get("x-forwarded-proto")
116
118
 
117
119
  if forwarded_host:
118
120
  scheme = forwarded_proto or "https"
119
- base = f"{scheme}://{forwarded_host.split(',')[0].strip()}"
120
- else:
121
- base = str(request.base_url).rstrip("/")
122
- # Force http for localhost (Google rejects https://localhost)
123
- if "://localhost" in base or "://127.0.0.1" in base:
124
- base = base.replace("https://", "http://")
121
+ return f"{scheme}://{forwarded_host.split(',')[0].strip()}"
122
+
123
+ base = str(request.base_url).rstrip("/")
124
+ if "://localhost" in base or "://127.0.0.1" in base:
125
+ base = base.replace("https://", "http://")
126
+ return base
127
+
128
+
129
+ def _build_redirect_uri(request: Request) -> str:
130
+ """Build the OAuth callback redirect URI from the current request.
131
+
132
+ Google requires redirect URIs to match *exactly* what's registered in GCP,
133
+ with no query parameters.
134
+ """
135
+ return f"{_build_app_origin(request)}/api/export/google-slides/auth/callback"
136
+
137
+
138
+ # Callback page template. The JS object braces are intentionally literal; the
139
+ # %TOKENS% are substituted below so the postMessage targets the explicit app
140
+ # origin (F-CR-3) instead of the wildcard '*'.
141
+ _CALLBACK_TEMPLATE = """
142
+ <html><body>
143
+ <h2>%TITLE%</h2>
144
+ <p>%MESSAGE%</p>
145
+ <script>
146
+ if (window.opener) {
147
+ window.opener.postMessage({ type: 'google-slides-auth', success: %SUCCESS% }, %ORIGIN%);
148
+ }
149
+ setTimeout(() => window.close(), %DELAY%);
150
+ </script>
151
+ </body></html>
152
+ """
125
153
 
126
- return f"{base}/api/export/google-slides/auth/callback"
154
+
155
+ def _callback_response(app_origin: str, *, success: bool) -> HTMLResponse:
156
+ """Render the popup callback page and clear the anti-CSRF state cookie.
157
+
158
+ ``postMessage`` targets ``app_origin`` explicitly (F-CR-3); ``json.dumps``
159
+ yields a safely-quoted JS string literal for the origin.
160
+ """
161
+ if success:
162
+ title, message, delay = "Authorization Successful", "You can close this window.", "1500"
163
+ else:
164
+ title = "Authorization Failed"
165
+ message = "Authorization could not be completed. Please close this window and try again."
166
+ delay = "3000"
167
+ body = (
168
+ _CALLBACK_TEMPLATE
169
+ .replace("%TITLE%", title)
170
+ .replace("%MESSAGE%", message)
171
+ .replace("%SUCCESS%", "true" if success else "false")
172
+ .replace("%ORIGIN%", json.dumps(app_origin))
173
+ .replace("%DELAY%", delay)
174
+ )
175
+ resp = HTMLResponse(content=body, status_code=200)
176
+ resp.delete_cookie(_OAUTH_STATE_COOKIE, path=_OAUTH_COOKIE_PATH)
177
+ return resp
127
178
 
128
179
 
129
180
  @router.get("/auth/status", response_model=AuthStatusResponse)
@@ -141,6 +192,7 @@ async def auth_status(db: Session = Depends(get_db)):
141
192
  @router.get("/auth/url", response_model=AuthUrlResponse)
142
193
  async def auth_url(
143
194
  request: Request,
195
+ response: Response,
144
196
  db: Session = Depends(get_db),
145
197
  ):
146
198
  """Generate the Google OAuth consent URL.
@@ -149,13 +201,26 @@ async def auth_url(
149
201
  passed via the OAuth ``state`` parameter so the callback can persist the
150
202
  token for the correct user — the redirect URI itself stays clean
151
203
  (no query params) to satisfy Google's exact-match requirement.
204
+
205
+ F-CR-3: an unguessable nonce is bound into both the ``state`` and a
206
+ short-lived cookie; the callback requires them to match.
152
207
  """
153
208
  try:
154
209
  auth = _get_auth(db)
155
210
  redirect_uri = _build_redirect_uri(request)
156
- state = json.dumps({"user": _get_user_identity()})
211
+ nonce = secrets.token_urlsafe(32)
212
+ state = json.dumps({"user": _get_user_identity(), "nonce": nonce})
157
213
  url = auth.get_auth_url(redirect_uri=redirect_uri, state=state)
158
214
 
215
+ response.set_cookie(
216
+ key=_OAUTH_STATE_COOKIE,
217
+ value=nonce,
218
+ max_age=600,
219
+ httponly=True,
220
+ secure=True,
221
+ samesite="lax", # sent on Google's top-level redirect back to us
222
+ path=_OAUTH_COOKIE_PATH,
223
+ )
159
224
  return AuthUrlResponse(url=url)
160
225
  except GoogleSlidesAuthError as exc:
161
226
  raise HTTPException(status_code=400, detail=str(exc)) from exc
@@ -184,12 +249,22 @@ async def auth_callback(
184
249
  them in the ``google_oauth_tokens`` table. Returns a small HTML page
185
250
  that notifies the opener window and closes itself.
186
251
  """
252
+ app_origin = _build_app_origin(request)
253
+ cookie_nonce = request.cookies.get(_OAUTH_STATE_COOKIE)
187
254
  try:
188
255
  state_data = json.loads(state) if state else {}
189
256
  user = state_data.get("user")
190
257
  if not user:
191
258
  raise ValueError("Missing user in OAuth state")
192
259
 
260
+ # F-CR-3: verify the anti-CSRF nonce BEFORE exchanging the code. The
261
+ # state nonce must match the cookie set when the auth URL was issued.
262
+ state_nonce = state_data.get("nonce")
263
+ if not cookie_nonce or not state_nonce or not secrets.compare_digest(
264
+ str(cookie_nonce), str(state_nonce)
265
+ ):
266
+ raise ValueError("OAuth state nonce mismatch")
267
+
193
268
  auth = _get_auth(db)
194
269
  redirect_uri = _build_redirect_uri(request)
195
270
  code_verifier = state_data.get("code_verifier")
@@ -198,39 +273,13 @@ async def auth_callback(
198
273
  "Google Slides OAuth callback successful",
199
274
  extra={"user": _get_user_identity()},
200
275
  )
201
- except Exception as exc:
276
+ except Exception:
277
+ # F-CR-2 (SDR-4437): never reflect the raw exception into the HTML page —
278
+ # it is logged server-side above. Show a static, generic failure message.
202
279
  logger.error("OAuth callback failed", exc_info=True)
203
- return HTMLResponse(
204
- content=f"""
205
- <html><body>
206
- <h2>Authorization Failed</h2>
207
- <p>{exc}</p>
208
- <script>
209
- if (window.opener) {{
210
- window.opener.postMessage({{ type: 'google-slides-auth', success: false }}, '*');
211
- }}
212
- setTimeout(() => window.close(), 3000);
213
- </script>
214
- </body></html>
215
- """,
216
- status_code=200,
217
- )
280
+ return _callback_response(app_origin, success=False)
218
281
 
219
- return HTMLResponse(
220
- content="""
221
- <html><body>
222
- <h2>Authorization Successful</h2>
223
- <p>You can close this window.</p>
224
- <script>
225
- if (window.opener) {
226
- window.opener.postMessage({ type: 'google-slides-auth', success: true }, '*');
227
- }
228
- setTimeout(() => window.close(), 1500);
229
- </script>
230
- </body></html>
231
- """,
232
- status_code=200,
233
- )
282
+ return _callback_response(app_origin, success=True)
234
283
 
235
284
 
236
285
  # -------------------------------------------------------------------------
@@ -284,7 +333,7 @@ async def start_google_slides_export(
284
333
  slide_deck = chat_service.get_slides(request_body.session_id)
285
334
  except Exception as exc:
286
335
  logger.error("Failed to fetch slides", exc_info=True)
287
- raise HTTPException(status_code=500, detail=f"Failed to fetch slides: {exc}") from exc
336
+ raise HTTPException(status_code=500, detail="Failed to fetch slides") from exc
288
337
 
289
338
  if not slide_deck or not slide_deck.get("slides"):
290
339
  raise HTTPException(status_code=404, detail="No slides available")
@@ -448,7 +497,7 @@ async def export_google_slides_from_records(
448
497
  )
449
498
  except Exception as exc:
450
499
  logger.error("Drive upload failed", exc_info=True)
451
- raise HTTPException(status_code=502, detail=f"Drive upload failed: {exc}") from exc
500
+ raise HTTPException(status_code=502, detail="Drive upload failed") from exc
452
501
 
453
502
  session_manager.set_google_slides_info(
454
503
  session_id=request.session_id,
@@ -598,7 +647,7 @@ async def export_google_slides_from_huashu(
598
647
  logger.error("Drive upload failed (huashu path)", exc_info=True)
599
648
  raise HTTPException(
600
649
  status_code=502,
601
- detail=f"Drive upload failed: {exc}",
650
+ detail="Drive upload failed",
602
651
  ) from exc
603
652
 
604
653
  session_manager.set_google_slides_info(
@@ -9,10 +9,7 @@ Session access is controlled by:
9
9
  """
10
10
 
11
11
  import asyncio
12
- import json
13
12
  import logging
14
- from datetime import datetime
15
- from pathlib import Path
16
13
  from typing import Optional
17
14
 
18
15
  from fastapi import APIRouter, Depends, HTTPException, Query
@@ -553,7 +550,7 @@ async def duplicate_session(
553
550
  logger.error(f"Failed to duplicate session: {e}", exc_info=True)
554
551
  raise HTTPException(
555
552
  status_code=500,
556
- detail=f"Failed to duplicate session: {str(e)}",
553
+ detail="Failed to duplicate session",
557
554
  ) from e
558
555
 
559
556
 
@@ -769,86 +766,9 @@ async def cleanup_expired_sessions():
769
766
  ) from e
770
767
 
771
768
 
772
- @router.post("/{session_id}/export")
773
- async def export_session(session_id: str):
774
- """Export full session data to logs/sessions/{session_id}.json for debugging.
775
-
776
- Exports:
777
- - Session info (id, timestamps, profile)
778
- - All chat messages (user + AI responses with full content)
779
- - Full slide deck (HTML, scripts, slide count)
780
-
781
- Args:
782
- session_id: Session to export
783
-
784
- Returns:
785
- Export confirmation with file path
786
- """
787
- try:
788
- # Permission check: require CAN_VIEW on the deck
789
- await asyncio.to_thread(
790
- _check_deck_permission_for_session, session_id, PermissionLevel.CAN_VIEW
791
- )
792
-
793
- session_manager = get_session_manager()
794
-
795
- # Get all session data
796
- session = await asyncio.to_thread(session_manager.get_session, session_id)
797
- messages = await asyncio.to_thread(session_manager.get_messages, session_id)
798
- slide_deck = await asyncio.to_thread(session_manager.get_slide_deck, session_id)
799
-
800
- # Build export data
801
- export_data = {
802
- "exported_at": datetime.utcnow().isoformat(),
803
- "session": session,
804
- "messages": messages,
805
- "slide_deck": slide_deck,
806
- "summary": {
807
- "message_count": len(messages),
808
- "slide_count": slide_deck.get("slide_count", 0) if slide_deck else 0,
809
- "user_messages": sum(1 for m in messages if m.get("role") == "user"),
810
- "ai_messages": sum(1 for m in messages if m.get("role") == "assistant"),
811
- }
812
- }
813
-
814
- # Ensure logs/sessions directory exists
815
- sessions_dir = Path("logs/sessions")
816
- sessions_dir.mkdir(parents=True, exist_ok=True)
817
-
818
- # Write to file
819
- export_path = sessions_dir / f"{session_id}.json"
820
- with open(export_path, "w", encoding="utf-8") as f:
821
- json.dump(export_data, f, indent=2, default=str)
822
-
823
- logger.info(
824
- "Session exported",
825
- extra={
826
- "session_id": session_id,
827
- "export_path": str(export_path),
828
- "message_count": len(messages),
829
- },
830
- )
831
-
832
- return {
833
- "status": "exported",
834
- "session_id": session_id,
835
- "export_path": str(export_path),
836
- "summary": export_data["summary"],
837
- }
838
-
839
- except SessionNotFoundError:
840
- raise HTTPException(
841
- status_code=404,
842
- detail=f"Session not found: {session_id}",
843
- )
844
- except HTTPException:
845
- raise
846
- except Exception as e:
847
- logger.error(f"Failed to export session: {e}", exc_info=True)
848
- raise HTTPException(
849
- status_code=500,
850
- detail="Export failed",
851
- ) from e
769
+ # F-CR-10 (SDR-4437): the debug-only POST /{session_id}/export endpoint was
770
+ # removed — it was unused by the frontend and dumped full session data (all chat
771
+ # messages + deck) to logs/sessions/{id}.json.
852
772
 
853
773
 
854
774
  # =========================================================================
@@ -109,7 +109,7 @@ def list_users(
109
109
  logger.error(f"Failed to list users: {e}", exc_info=True)
110
110
  raise HTTPException(
111
111
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
112
- detail=f"Failed to list users: {e}",
112
+ detail="Failed to list users",
113
113
  )
114
114
 
115
115
 
@@ -149,7 +149,7 @@ def list_groups(
149
149
  logger.error(f"Failed to list groups: {e}", exc_info=True)
150
150
  raise HTTPException(
151
151
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
152
- detail=f"Failed to list groups: {e}",
152
+ detail="Failed to list groups",
153
153
  )
154
154
 
155
155
 
@@ -203,5 +203,5 @@ def search_identities(
203
203
  logger.error(f"Failed to search identities: {e}", exc_info=True)
204
204
  raise HTTPException(
205
205
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
206
- detail=f"Failed to search identities: {e}",
206
+ detail="Failed to search identities",
207
207
  )
@@ -123,7 +123,7 @@ async def configure_workspace(request: ConfigureWorkspaceRequest):
123
123
  logger.error(f"Failed to configure workspace: {e}")
124
124
  raise HTTPException(
125
125
  status_code=500,
126
- detail=f"Failed to save configuration: {str(e)}"
126
+ detail="Failed to save configuration"
127
127
  )
128
128
 
129
129
 
@@ -154,5 +154,5 @@ async def test_connection():
154
154
  logger.error(f"Connection test failed: {e}")
155
155
  raise HTTPException(
156
156
  status_code=400,
157
- detail=f"Connection failed: {str(e)}"
157
+ detail="Connection failed"
158
158
  )