databricks-tellr-app 0.4.3.dev3401__tar.gz → 0.4.3.dev3403__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 (168) hide show
  1. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/PKG-INFO +1 -1
  2. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/databricks_tellr_app.egg-info/PKG-INFO +1 -1
  3. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/databricks_tellr_app.egg-info/SOURCES.txt +2 -0
  4. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/pyproject.toml +1 -1
  5. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/chat.py +6 -31
  6. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/design_system_service.py +15 -0
  7. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/image_service.py +15 -0
  8. databricks_tellr_app-0.4.3.dev3403/src/services/svg_sanitizer.py +414 -0
  9. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/README.md +0 -0
  10. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/databricks_tellr_app/__init__.py +0 -0
  11. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/databricks_tellr_app/run.py +0 -0
  12. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/databricks_tellr_app.egg-info/dependency_links.txt +0 -0
  13. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/databricks_tellr_app.egg-info/requires.txt +0 -0
  14. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/databricks_tellr_app.egg-info/top_level.txt +0 -0
  15. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/setup.cfg +0 -0
  16. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/setup.py +0 -0
  17. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/__init__.py +0 -0
  18. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/__init__.py +0 -0
  19. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/_otel_bootstrap.py +0 -0
  20. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/fixtures/tour_demo_deck.json +0 -0
  21. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/main.py +0 -0
  22. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/mcp_auth.py +0 -0
  23. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/mcp_server.py +0 -0
  24. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/middleware/__init__.py +0 -0
  25. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/middleware/csrf.py +0 -0
  26. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/middleware/request_logging.py +0 -0
  27. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/middleware/security_headers.py +0 -0
  28. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/__init__.py +0 -0
  29. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/_authz.py +0 -0
  30. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/admin.py +0 -0
  31. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/admin_usage.py +0 -0
  32. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/agent_config.py +0 -0
  33. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/deck_contributors.py +0 -0
  34. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/export.py +0 -0
  35. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/feedback.py +0 -0
  36. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/google_slides.py +0 -0
  37. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/images.py +0 -0
  38. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/local_version.py +0 -0
  39. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/profiles.py +0 -0
  40. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/sessions.py +0 -0
  41. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/settings/__init__.py +0 -0
  42. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/settings/contributors.py +0 -0
  43. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/settings/deck_prompts.py +0 -0
  44. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/settings/design_systems.py +0 -0
  45. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/settings/identities.py +0 -0
  46. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/settings/slide_styles.py +0 -0
  47. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/setup.py +0 -0
  48. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/slides.py +0 -0
  49. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/tools.py +0 -0
  50. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/tour.py +0 -0
  51. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/verification.py +0 -0
  52. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/routes/version.py +0 -0
  53. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/schemas/__init__.py +0 -0
  54. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/schemas/agent_config.py +0 -0
  55. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/schemas/feedback.py +0 -0
  56. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/schemas/requests.py +0 -0
  57. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/schemas/responses.py +0 -0
  58. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/schemas/settings/__init__.py +0 -0
  59. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/schemas/settings/requests.py +0 -0
  60. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/schemas/settings/responses.py +0 -0
  61. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/schemas/streaming.py +0 -0
  62. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/services/__init__.py +0 -0
  63. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/services/chat_service.py +0 -0
  64. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/services/export_job_queue.py +0 -0
  65. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/services/feedback_service.py +0 -0
  66. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/services/job_queue.py +0 -0
  67. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/services/session_manager.py +0 -0
  68. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/services/session_naming.py +0 -0
  69. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/services/usage_events.py +0 -0
  70. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/services/usage_service.py +0 -0
  71. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/utils/__init__.py +0 -0
  72. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/api/utils/validation.py +0 -0
  73. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/core/__init__.py +0 -0
  74. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/core/config_loader.py +0 -0
  75. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/core/context_utils.py +0 -0
  76. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/core/database.py +0 -0
  77. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/core/databricks_client.py +0 -0
  78. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/core/defaults.py +0 -0
  79. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/core/encryption.py +0 -0
  80. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/core/init_default_profile.py +0 -0
  81. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/core/lakebase.py +0 -0
  82. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/core/migrate_profiles_to_agent_config.py +0 -0
  83. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/core/mlflow_agent_spans.py +0 -0
  84. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/core/mlflow_tracing.py +0 -0
  85. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/core/otel_logging.py +0 -0
  86. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/core/permission_context.py +0 -0
  87. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/core/prompt_modules.py +0 -0
  88. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/core/settings_db.py +0 -0
  89. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/core/user_context.py +0 -0
  90. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/__init__.py +0 -0
  91. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/__init__.py +0 -0
  92. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/deck_contributor.py +0 -0
  93. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/design_system.py +0 -0
  94. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/encryption_key.py +0 -0
  95. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/feedback.py +0 -0
  96. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/genie_space.py +0 -0
  97. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/google_global_credentials.py +0 -0
  98. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/google_oauth_token.py +0 -0
  99. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/identity.py +0 -0
  100. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/image.py +0 -0
  101. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/profile.py +0 -0
  102. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/profile_contributor.py +0 -0
  103. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/prompts.py +0 -0
  104. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/request_log.py +0 -0
  105. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/session.py +0 -0
  106. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/slide_deck_prompt.py +0 -0
  107. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/slide_style_library.py +0 -0
  108. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/usage_event.py +0 -0
  109. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/models/user_preference.py +0 -0
  110. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/database/types.py +0 -0
  111. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/domain/__init__.py +0 -0
  112. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/domain/slide.py +0 -0
  113. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/domain/slide_deck.py +0 -0
  114. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/__init__.py +0 -0
  115. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/agent.py +0 -0
  116. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/agent_factory.py +0 -0
  117. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/config_service.py +0 -0
  118. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/config_validator.py +0 -0
  119. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/converter_jail/__init__.py +0 -0
  120. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/converter_jail/ast_guard.py +0 -0
  121. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/converter_jail/codeprep.py +0 -0
  122. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/converter_jail/gslides_runner.py +0 -0
  123. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/converter_jail/jail.py +0 -0
  124. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/converter_jail/pptx_runner.py +0 -0
  125. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/converter_jail/protocol.py +0 -0
  126. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/design_system_compiler.py +0 -0
  127. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/design_system_templates.py +0 -0
  128. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/drive_uploader.py +0 -0
  129. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/evaluation/__init__.py +0 -0
  130. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/evaluation/llm_judge.py +0 -0
  131. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/genie_service.py +0 -0
  132. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/google_slides_auth.py +0 -0
  133. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/google_slides_prompts_defaults.py +0 -0
  134. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/html_to_google_slides.py +0 -0
  135. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/html_to_pptx.py +0 -0
  136. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/identity_provider.py +0 -0
  137. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/identity_providers/__init__.py +0 -0
  138. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/identity_providers/account_provider.py +0 -0
  139. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/identity_providers/local_provider.py +0 -0
  140. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/identity_providers/workspace_provider.py +0 -0
  141. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/image_tools.py +0 -0
  142. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/permission_service.py +0 -0
  143. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/pptx_from_html_huashu.py +0 -0
  144. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/pptx_from_records.py +0 -0
  145. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/pptx_prompts_defaults.py +0 -0
  146. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/profile_service.py +0 -0
  147. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/streaming_callback.py +0 -0
  148. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/tools/__init__.py +0 -0
  149. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/tools/agent_bricks_tool.py +0 -0
  150. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/tools/ds_asset_tool.py +0 -0
  151. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/tools/genie_tool.py +0 -0
  152. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/tools/mcp_tool.py +0 -0
  153. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/tools/model_endpoint_tool.py +0 -0
  154. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/tools/vector_tool.py +0 -0
  155. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/services/validator.py +0 -0
  156. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/utils/__init__.py +0 -0
  157. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/utils/css_utils.py +0 -0
  158. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/utils/ds_asset_utils.py +0 -0
  159. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/utils/error_handling.py +0 -0
  160. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/utils/html_safety.py +0 -0
  161. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/utils/html_utils.py +0 -0
  162. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/utils/image_utils.py +0 -0
  163. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/utils/js_validator.py +0 -0
  164. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/utils/logging_config.py +0 -0
  165. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/utils/pi_filter.py +0 -0
  166. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/utils/slide_hash.py +0 -0
  167. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/src/utils/spotlight.py +0 -0
  168. {databricks_tellr_app-0.4.3.dev3401 → databricks_tellr_app-0.4.3.dev3403}/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.dev3401
3
+ Version: 0.4.3.dev3403
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.dev3401
3
+ Version: 0.4.3.dev3403
4
4
  Summary: Tellr application package for Databricks Apps
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -124,6 +124,7 @@ setup.py
124
124
  ./src/services/pptx_prompts_defaults.py
125
125
  ./src/services/profile_service.py
126
126
  ./src/services/streaming_callback.py
127
+ ./src/services/svg_sanitizer.py
127
128
  ./src/services/validator.py
128
129
  ./src/services/converter_jail/__init__.py
129
130
  ./src/services/converter_jail/ast_guard.py
@@ -286,6 +287,7 @@ src/services/pptx_from_records.py
286
287
  src/services/pptx_prompts_defaults.py
287
288
  src/services/profile_service.py
288
289
  src/services/streaming_callback.py
290
+ src/services/svg_sanitizer.py
289
291
  src/services/validator.py
290
292
  src/services/converter_jail/__init__.py
291
293
  src/services/converter_jail/ast_guard.py
@@ -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.dev3401"
7
+ version = "0.4.3.dev3403"
8
8
  description = "Tellr application package for Databricks Apps"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -25,6 +25,7 @@ from src.api.schemas.agent_config import normalize_style_source_exclusivity
25
25
  from src.api.schemas.requests import ChatRequest
26
26
  from src.api.schemas.responses import ChatResponse
27
27
  from src.api.schemas.streaming import StreamEvent, StreamEventType
28
+ from src.api.routes._authz import _check_deck_permission_for_session
28
29
  from src.api.services.chat_service import get_chat_service
29
30
  from src.api.services.job_queue import enqueue_job
30
31
  from src.api.services.session_manager import SessionNotFoundError, get_session_manager
@@ -120,32 +121,6 @@ def _check_chat_permission(session_id: str, db: DBSession) -> None:
120
121
  )
121
122
 
122
123
 
123
- def _require_chat_request_owner(session_id: str) -> None:
124
- """Allow polling only for the session that owns the chat request.
125
-
126
- ChatRequest rows are bound to a session, and conversations are private
127
- (same rule as ``GET /api/sessions/{id}/messages``): only the session
128
- creator may read them. A viewer's contributor session is a different
129
- session with a different creator, so deck-level CAN_VIEW is not enough.
130
-
131
- Raises:
132
- HTTPException 404: Session no longer exists.
133
- HTTPException 403: Caller is not the session creator.
134
- """
135
- session_manager = get_session_manager()
136
- try:
137
- session_info = session_manager.get_session(session_id)
138
- except SessionNotFoundError:
139
- raise HTTPException(status_code=404, detail="Request not found")
140
-
141
- current_user = get_current_user()
142
- if not current_user or session_info.get("created_by") != current_user:
143
- raise HTTPException(
144
- status_code=403,
145
- detail="Conversations are private. Only the session creator can view chat events.",
146
- )
147
-
148
-
149
124
  def _apply_org_default_style_source(
150
125
  agent_config_data: dict,
151
126
  *,
@@ -696,21 +671,21 @@ async def poll_chat(
696
671
  Dictionary with status, events, last_message_id, and result
697
672
 
698
673
  Raises:
699
- HTTPException: 404 if request not found, 403 if caller is not the
700
- session creator
674
+ HTTPException: 404 if request not found
701
675
  """
702
676
  session_manager = get_session_manager()
703
677
 
704
678
  # SDR-4437 (chat-poll IDOR): a request_id must not grant access to another
705
679
  # user's chat events/result. ChatRequest rows are session-bound — resolve
706
- # the session and require the caller to be its creator (F-CR-31: same
707
- # privacy rule as /messages; deck CAN_VIEW must not expose chat events).
680
+ # the session and require CAN_VIEW on the deck.
708
681
  session_id = await asyncio.to_thread(
709
682
  session_manager.get_session_id_for_request, request_id
710
683
  )
711
684
  if session_id is None:
712
685
  raise HTTPException(status_code=404, detail="Request not found")
713
- await asyncio.to_thread(_require_chat_request_owner, session_id)
686
+ await asyncio.to_thread(
687
+ _check_deck_permission_for_session, session_id, PermissionLevel.CAN_VIEW
688
+ )
714
689
 
715
690
  chat_request = await asyncio.to_thread(
716
691
  session_manager.get_chat_request, request_id
@@ -74,6 +74,7 @@ from src.database.models.design_system import (
74
74
  DesignSystemToken,
75
75
  )
76
76
  from src.services.design_system_compiler import recompute_compiled_style_content
77
+ from src.services.svg_sanitizer import looks_like_svg, sanitize_svg
77
78
 
78
79
  logger = logging.getLogger(__name__)
79
80
 
@@ -2164,6 +2165,20 @@ def _collect_assets_and_files(
2164
2165
  mime = sniffed
2165
2166
  else:
2166
2167
  mime = _guess_mime(rel)
2168
+ if mime == "image/svg+xml":
2169
+ try:
2170
+ data = sanitize_svg(data)
2171
+ except ValueError as exc:
2172
+ raise DesignSystemImportError(
2173
+ f"Bundle entry '{rel}' is not a valid SVG: {exc}"
2174
+ ) from exc
2175
+ elif looks_like_svg(data):
2176
+ # Extension says raster/font/etc. but the bytes are SVG:
2177
+ # never trust the name to skip sanitization.
2178
+ raise DesignSystemImportError(
2179
+ f"Bundle entry '{rel}' contains SVG content but does not "
2180
+ "have an .svg extension"
2181
+ )
2167
2182
  width, height = _image_dimensions(data, mime)
2168
2183
  asset = DesignSystemAsset(
2169
2184
  kind=kind,
@@ -11,6 +11,7 @@ from sqlalchemy.dialects.postgresql import JSONB
11
11
  from sqlalchemy.orm import Query, Session
12
12
 
13
13
  from src.database.models.image import ImageAsset
14
+ from src.services.svg_sanitizer import looks_like_svg, sanitize_svg
14
15
 
15
16
  logger = logging.getLogger(__name__)
16
17
 
@@ -41,6 +42,20 @@ def upload_image(
41
42
  if len(file_content) > MAX_FILE_SIZE:
42
43
  raise ValueError(f"File too large: {len(file_content)} bytes (max {MAX_FILE_SIZE})")
43
44
 
45
+ # The client-declared MIME type is untrusted: decide on the CONTENT.
46
+ # SVG can carry script, so it is always sanitized; SVG bytes declared as
47
+ # any other type are rejected rather than stored under a raster label.
48
+ if mime_type == "image/svg+xml":
49
+ try:
50
+ file_content = sanitize_svg(file_content)
51
+ except ValueError as exc:
52
+ raise ValueError(f"Invalid SVG upload: {exc}") from exc
53
+ elif looks_like_svg(file_content):
54
+ raise ValueError(
55
+ f"File content is SVG but was declared as {mime_type}; "
56
+ "upload it as image/svg+xml."
57
+ )
58
+
44
59
  # Check for duplicate original_filename among active images (case-insensitive).
45
60
  # Ephemeral images (paste-to-chat) skip this check — they use throwaway names
46
61
  # and should never block each other.
@@ -0,0 +1,414 @@
1
+ """Server-side sanitization for SVG images before they are stored."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from urllib.parse import urlsplit
7
+
8
+ from lxml import etree # type: ignore[import-untyped]
9
+
10
+ SVG_NAMESPACE = "http://www.w3.org/2000/svg"
11
+
12
+ _ALLOWED_ELEMENTS = frozenset(
13
+ {
14
+ "svg",
15
+ "g",
16
+ "defs",
17
+ "symbol",
18
+ "use",
19
+ "title",
20
+ "desc",
21
+ "switch",
22
+ "view",
23
+ "path",
24
+ "rect",
25
+ "circle",
26
+ "ellipse",
27
+ "line",
28
+ "polyline",
29
+ "polygon",
30
+ "text",
31
+ "tspan",
32
+ "textPath",
33
+ "a",
34
+ "image",
35
+ "style",
36
+ "linearGradient",
37
+ "radialGradient",
38
+ "stop",
39
+ "pattern",
40
+ "marker",
41
+ "mask",
42
+ "clipPath",
43
+ "filter",
44
+ "feBlend",
45
+ "feColorMatrix",
46
+ "feComponentTransfer",
47
+ "feComposite",
48
+ "feConvolveMatrix",
49
+ "feDiffuseLighting",
50
+ "feDisplacementMap",
51
+ "feDistantLight",
52
+ "feDropShadow",
53
+ "feFlood",
54
+ "feFuncA",
55
+ "feFuncB",
56
+ "feFuncG",
57
+ "feFuncR",
58
+ "feGaussianBlur",
59
+ "feImage",
60
+ "feMerge",
61
+ "feMergeNode",
62
+ "feMorphology",
63
+ "feOffset",
64
+ "fePointLight",
65
+ "feSpecularLighting",
66
+ "feSpotLight",
67
+ "feTile",
68
+ "feTurbulence",
69
+ "animate",
70
+ "animateMotion",
71
+ "animateTransform",
72
+ "set",
73
+ "mpath",
74
+ }
75
+ )
76
+
77
+ _ALLOWED_ATTRIBUTES = frozenset(
78
+ {
79
+ "id",
80
+ "class",
81
+ "style",
82
+ "transform",
83
+ "transform-origin",
84
+ "clip-path",
85
+ "clip-rule",
86
+ "mask",
87
+ "filter",
88
+ "opacity",
89
+ "fill",
90
+ "fill-opacity",
91
+ "fill-rule",
92
+ "stroke",
93
+ "stroke-dasharray",
94
+ "stroke-dashoffset",
95
+ "stroke-linecap",
96
+ "stroke-linejoin",
97
+ "stroke-miterlimit",
98
+ "stroke-opacity",
99
+ "stroke-width",
100
+ "paint-order",
101
+ "color",
102
+ "color-interpolation",
103
+ "color-interpolation-filters",
104
+ "display",
105
+ "visibility",
106
+ "systemLanguage",
107
+ "requiredFeatures",
108
+ "requiredExtensions",
109
+ "lang",
110
+ "space",
111
+ "role",
112
+ "tabindex",
113
+ "version",
114
+ "baseProfile",
115
+ "width",
116
+ "height",
117
+ "viewBox",
118
+ "preserveAspectRatio",
119
+ "x",
120
+ "y",
121
+ "dx",
122
+ "dy",
123
+ "zoomAndPan",
124
+ "d",
125
+ "points",
126
+ "rx",
127
+ "ry",
128
+ "cx",
129
+ "cy",
130
+ "r",
131
+ "x1",
132
+ "x2",
133
+ "y1",
134
+ "y2",
135
+ "rotate",
136
+ "textLength",
137
+ "lengthAdjust",
138
+ "font-family",
139
+ "font-size",
140
+ "font-style",
141
+ "font-variant",
142
+ "font-weight",
143
+ "letter-spacing",
144
+ "word-spacing",
145
+ "text-decoration",
146
+ "text-anchor",
147
+ "dominant-baseline",
148
+ "alignment-baseline",
149
+ "baseline-shift",
150
+ "writing-mode",
151
+ "gradientUnits",
152
+ "gradientTransform",
153
+ "spreadMethod",
154
+ "href",
155
+ "offset",
156
+ "stop-color",
157
+ "stop-opacity",
158
+ "patternUnits",
159
+ "patternContentUnits",
160
+ "patternTransform",
161
+ "markerWidth",
162
+ "markerHeight",
163
+ "markerUnits",
164
+ "refX",
165
+ "refY",
166
+ "orient",
167
+ "clipPathUnits",
168
+ "maskUnits",
169
+ "maskContentUnits",
170
+ "filterUnits",
171
+ "primitiveUnits",
172
+ "in",
173
+ "in2",
174
+ "result",
175
+ "mode",
176
+ "values",
177
+ "type",
178
+ "tableValues",
179
+ "slope",
180
+ "intercept",
181
+ "amplitude",
182
+ "exponent",
183
+ "k1",
184
+ "k2",
185
+ "k3",
186
+ "k4",
187
+ "operator",
188
+ "radius",
189
+ "stdDeviation",
190
+ "xChannelSelector",
191
+ "yChannelSelector",
192
+ "scale",
193
+ "flood-color",
194
+ "flood-opacity",
195
+ "kernelMatrix",
196
+ "divisor",
197
+ "bias",
198
+ "targetX",
199
+ "targetY",
200
+ "edgeMode",
201
+ "kernelUnitLength",
202
+ "preserveAlpha",
203
+ "lighting-color",
204
+ "surfaceScale",
205
+ "diffuseConstant",
206
+ "specularConstant",
207
+ "specularExponent",
208
+ "pointsAtX",
209
+ "pointsAtY",
210
+ "pointsAtZ",
211
+ "limitingConeAngle",
212
+ "azimuth",
213
+ "elevation",
214
+ "seed",
215
+ "numOctaves",
216
+ "baseFrequency",
217
+ "stitchTiles",
218
+ "attributeName",
219
+ "attributeType",
220
+ "begin",
221
+ "end",
222
+ "dur",
223
+ "repeatCount",
224
+ "repeatDur",
225
+ "from",
226
+ "to",
227
+ "by",
228
+ "keyTimes",
229
+ "keySplines",
230
+ "keyPoints",
231
+ "calcMode",
232
+ "additive",
233
+ "accumulate",
234
+ "path",
235
+ "startOffset",
236
+ "method",
237
+ "spacing",
238
+ "crossorigin",
239
+ "decoding",
240
+ "loading",
241
+ "target",
242
+ "download",
243
+ "rel",
244
+ }
245
+ )
246
+
247
+ _URL_ATTRIBUTES = frozenset({"href"})
248
+ _ANIMATION_ELEMENTS = frozenset({"animate", "animateMotion", "animateTransform", "set"})
249
+ _ANIMATION_FORBIDDEN_TARGETS = frozenset({"href", "style"})
250
+ _SAFE_DATA_IMAGE_TYPES = frozenset({"png", "jpeg", "jpg", "gif", "webp"})
251
+ _UNSAFE_URL_PATTERN = re.compile(
252
+ r"(?:javascript|vbscript|livescript|mocha):|data:image/svg\+xml",
253
+ re.IGNORECASE,
254
+ )
255
+
256
+
257
+ def _local_name(value: str) -> str:
258
+ return value.rsplit("}", 1)[-1].rsplit(":", 1)[-1]
259
+
260
+
261
+ def _element_local_name(element: etree._Element) -> str:
262
+ return etree.QName(element).localname
263
+
264
+
265
+ def _is_allowed_element(element: etree._Element) -> bool:
266
+ return _element_local_name(element) in _ALLOWED_ELEMENTS
267
+
268
+
269
+ def _normalized_url(value: str) -> str:
270
+ characters = (character for character in value if character not in "\t\n\r\f\v")
271
+ return "".join(characters).strip()
272
+
273
+
274
+ def _is_safe_url(value: str) -> bool:
275
+ normalized = _normalized_url(value)
276
+ if not normalized or normalized.startswith("#"):
277
+ return True
278
+
279
+ parsed = urlsplit(normalized)
280
+ scheme = parsed.scheme.lower()
281
+ if not scheme or scheme in {"http", "https", "mailto"}:
282
+ return True
283
+ if scheme != "data":
284
+ return False
285
+
286
+ media_type = parsed.path.split(";", 1)[0].lower()
287
+ image_type = media_type.removeprefix("image/")
288
+ return image_type in _SAFE_DATA_IMAGE_TYPES
289
+
290
+
291
+ def _has_external_use_reference(element: etree._Element) -> bool:
292
+ return any(
293
+ _local_name(name) == "href" and not _normalized_url(value).startswith("#")
294
+ for name, value in element.attrib.items()
295
+ )
296
+
297
+
298
+ def _animation_targets_forbidden_attribute(element: etree._Element) -> bool:
299
+ target = element.get("attributeName")
300
+ if target is None:
301
+ return False
302
+ local_target = _local_name(target)
303
+ return local_target.startswith("on") or local_target in _ANIMATION_FORBIDDEN_TARGETS
304
+
305
+
306
+ def _contains_unsafe_url(value: str) -> bool:
307
+ return _UNSAFE_URL_PATTERN.search(_normalized_url(value)) is not None
308
+
309
+
310
+ def _sanitize_attributes(root: etree._Element) -> None:
311
+ for element in root.iter():
312
+ for name, value in list(element.attrib.items()):
313
+ local_name = _local_name(name)
314
+ if local_name not in _ALLOWED_ATTRIBUTES:
315
+ del element.attrib[name]
316
+ continue
317
+ if local_name in _URL_ATTRIBUTES and not _is_safe_url(value):
318
+ del element.attrib[name]
319
+ elif local_name == "style" and _contains_unsafe_url(value):
320
+ del element.attrib[name]
321
+
322
+ if _element_local_name(element) == "style" and _contains_unsafe_url(
323
+ element.text or ""
324
+ ):
325
+ element.text = None
326
+
327
+
328
+ _RASTER_MAGICS = (
329
+ b"\x89PNG\r\n\x1a\n",
330
+ b"\xff\xd8\xff",
331
+ b"GIF87a",
332
+ b"GIF89a",
333
+ )
334
+ _SNIFF_WINDOW = 4096
335
+ # An SVG document: optional BOM/whitespace, any XML prolog (declaration, comments,
336
+ # PIs, DOCTYPE with optional internal subset), then ``<svg`` as the ROOT element.
337
+ # Anchoring on the root (not a substring) keeps CSS/HTML/text that merely mentions
338
+ # ``<svg`` (e.g. a ``data:image/svg+xml,<svg ...>`` URI) from being treated as SVG.
339
+ _SVG_ROOT_RE = re.compile(
340
+ r"\A\ufeff?\s*"
341
+ r"(?:<\?.*?\?>\s*|<!--.*?-->\s*|<!DOCTYPE(?:[^>\[]|\[.*?\])*>\s*)*"
342
+ r"<(?:[\w.-]+:)?svg[\s/>]",
343
+ re.IGNORECASE | re.DOTALL,
344
+ )
345
+
346
+
347
+ def looks_like_svg(content: bytes) -> bool:
348
+ """Content sniff: True if the bytes look like an SVG document.
349
+
350
+ Used so a client-declared MIME type (e.g. ``image/png``) is never trusted
351
+ to decide whether sanitization is needed. Content that starts with a known
352
+ raster magic number is not SVG; otherwise it is SVG only if ``<svg`` is the
353
+ root element (after any XML prolog) within the first few KB (UTF-8/ASCII or
354
+ BOM-marked UTF-16).
355
+ """
356
+ head = content[:_SNIFF_WINDOW]
357
+ if head.startswith(_RASTER_MAGICS):
358
+ return False
359
+ if head.startswith((b"\xff\xfe", b"\xfe\xff")):
360
+ text = head.decode("utf-16", errors="ignore")
361
+ else:
362
+ text = head.decode("utf-8", errors="ignore")
363
+ return _SVG_ROOT_RE.match(text) is not None
364
+
365
+
366
+ def sanitize_svg(content: bytes) -> bytes:
367
+ """Return a sanitized SVG, rejecting malformed or non-SVG XML input."""
368
+ parser = etree.XMLParser(
369
+ resolve_entities=False,
370
+ no_network=True,
371
+ load_dtd=False,
372
+ huge_tree=False,
373
+ remove_comments=True,
374
+ remove_pis=True,
375
+ )
376
+
377
+ try:
378
+ root = etree.fromstring(content, parser=parser)
379
+ except etree.XMLSyntaxError as exc:
380
+ raise ValueError("SVG must be well-formed XML") from exc
381
+
382
+ if root is None:
383
+ raise ValueError("SVG document is empty")
384
+
385
+ root_qname = etree.QName(root)
386
+ if root_qname.localname != "svg" or root_qname.namespace not in {None, SVG_NAMESPACE}:
387
+ raise ValueError("SVG root element is required")
388
+
389
+ if root.getroottree().docinfo.doctype:
390
+ raise ValueError("SVG DOCTYPE declarations are not allowed")
391
+
392
+ elements_to_remove = []
393
+ for element in root.iter():
394
+ if element is root:
395
+ continue
396
+
397
+ local_name = _element_local_name(element)
398
+ if not _is_allowed_element(element):
399
+ elements_to_remove.append(element)
400
+ elif local_name == "use" and _has_external_use_reference(element):
401
+ elements_to_remove.append(element)
402
+ elif local_name in _ANIMATION_ELEMENTS and _animation_targets_forbidden_attribute(
403
+ element
404
+ ):
405
+ elements_to_remove.append(element)
406
+
407
+ for element in elements_to_remove:
408
+ parent = element.getparent()
409
+ if parent is not None:
410
+ parent.remove(element)
411
+
412
+ _sanitize_attributes(root)
413
+
414
+ return etree.tostring(root, encoding="utf-8", xml_declaration=True)