classifyre-cli 0.4.11__tar.gz → 0.4.12__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 (183) hide show
  1. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/.turbo/turbo-build.log +1 -1
  2. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/PKG-INFO +1 -1
  3. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/package.json +1 -1
  4. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/pyproject.toml +1 -1
  5. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/models/generated_input.py +32 -4
  6. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/databricks/source.py +61 -8
  7. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/uv.lock +164 -134
  8. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/.gitignore +0 -0
  9. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/.python-version +0 -0
  10. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/README.md +0 -0
  11. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/main.py +0 -0
  12. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/scripts/generate_models.py +0 -0
  13. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/__init__.py +0 -0
  14. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/__init__.py +0 -0
  15. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/base.py +0 -0
  16. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/broken_links/__init__.py +0 -0
  17. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/broken_links/detector.py +0 -0
  18. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/config.py +0 -0
  19. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/content/__init__.py +0 -0
  20. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/custom/__init__.py +0 -0
  21. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/custom/detector.py +0 -0
  22. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/custom/extractor.py +0 -0
  23. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/custom/runners/__init__.py +0 -0
  24. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/custom/runners/_base.py +0 -0
  25. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/custom/runners/_factory.py +0 -0
  26. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/custom/runners/_feature_extraction.py +0 -0
  27. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/custom/runners/_gliner2.py +0 -0
  28. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/custom/runners/_image_classification.py +0 -0
  29. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/custom/runners/_llm.py +0 -0
  30. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/custom/runners/_object_detection.py +0 -0
  31. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/custom/runners/_regex.py +0 -0
  32. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/custom/runners/_text_classification.py +0 -0
  33. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/custom/trainer.py +0 -0
  34. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/dependencies.py +0 -0
  35. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/pii/__init__.py +0 -0
  36. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/pii/detector.py +0 -0
  37. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/secrets/__init__.py +0 -0
  38. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/secrets/detector.py +0 -0
  39. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/threat/__init__.py +0 -0
  40. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/threat/code_security_detector.py +0 -0
  41. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/detectors/threat/yara_detector.py +0 -0
  42. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/main.py +0 -0
  43. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/models/generated_detectors.py +0 -0
  44. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/models/generated_single_asset_scan_results.py +0 -0
  45. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/outputs/__init__.py +0 -0
  46. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/outputs/base.py +0 -0
  47. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/outputs/console.py +0 -0
  48. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/outputs/factory.py +0 -0
  49. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/outputs/file.py +0 -0
  50. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/outputs/rest.py +0 -0
  51. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/pipeline/__init__.py +0 -0
  52. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/pipeline/content_provider.py +0 -0
  53. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/pipeline/detector_pipeline.py +0 -0
  54. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/pipeline/parsed_content_provider.py +0 -0
  55. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/pipeline/worker_pool.py +0 -0
  56. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sandbox/__init__.py +0 -0
  57. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sandbox/runner.py +0 -0
  58. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/__init__.py +0 -0
  59. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/atlassian_common.py +0 -0
  60. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/azure_blob_storage/__init__.py +0 -0
  61. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/azure_blob_storage/source.py +0 -0
  62. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/base.py +0 -0
  63. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/confluence/__init__.py +0 -0
  64. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/confluence/source.py +0 -0
  65. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/databricks/__init__.py +0 -0
  66. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/dependencies.py +0 -0
  67. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/google_cloud_storage/__init__.py +0 -0
  68. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/google_cloud_storage/source.py +0 -0
  69. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/hive/__init__.py +0 -0
  70. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/hive/source.py +0 -0
  71. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/jira/__init__.py +0 -0
  72. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/jira/source.py +0 -0
  73. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/mongodb/__init__.py +0 -0
  74. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/mongodb/source.py +0 -0
  75. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/mssql/__init__.py +0 -0
  76. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/mssql/source.py +0 -0
  77. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/mysql/__init__.py +0 -0
  78. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/mysql/source.py +0 -0
  79. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/neo4j/__init__.py +0 -0
  80. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/neo4j/source.py +0 -0
  81. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/object_storage/base.py +0 -0
  82. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/oracle/__init__.py +0 -0
  83. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/oracle/source.py +0 -0
  84. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/postgresql/__init__.py +0 -0
  85. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/postgresql/source.py +0 -0
  86. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/powerbi/__init__.py +0 -0
  87. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/powerbi/source.py +0 -0
  88. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/recipe_normalizer.py +0 -0
  89. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/s3_compatible_storage/README.md +0 -0
  90. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/s3_compatible_storage/__init__.py +0 -0
  91. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/s3_compatible_storage/source.py +0 -0
  92. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/servicedesk/__init__.py +0 -0
  93. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/servicedesk/source.py +0 -0
  94. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/slack/__init__.py +0 -0
  95. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/slack/source.py +0 -0
  96. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/snowflake/__init__.py +0 -0
  97. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/snowflake/source.py +0 -0
  98. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/sqlite/__init__.py +0 -0
  99. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/sqlite/source.py +0 -0
  100. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/tableau/__init__.py +0 -0
  101. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/tableau/source.py +0 -0
  102. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/tabular_base.py +0 -0
  103. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/tabular_utils.py +0 -0
  104. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/wordpress/__init__.py +0 -0
  105. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/sources/wordpress/source.py +0 -0
  106. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/telemetry.py +0 -0
  107. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/utils/__init__.py +0 -0
  108. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/utils/content_extraction.py +0 -0
  109. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/utils/embedded_images.py +0 -0
  110. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/utils/file_parser.py +0 -0
  111. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/utils/file_to_images.py +0 -0
  112. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/utils/hashing.py +0 -0
  113. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/utils/uv_sync.py +0 -0
  114. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/src/utils/validation.py +0 -0
  115. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/__init__.py +0 -0
  116. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/conftest.py +0 -0
  117. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/__init__.py +0 -0
  118. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/broken_links/test_broken_links_detector.py +0 -0
  119. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/conftest.py +0 -0
  120. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/content/__init__.py +0 -0
  121. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/custom/__init__.py +0 -0
  122. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/custom/conftest.py +0 -0
  123. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/custom/test_invoice_extraction.py +0 -0
  124. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/custom/test_llm_runner.py +0 -0
  125. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/custom/test_pipeline_integration.py +0 -0
  126. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/custom/test_regex_runner.py +0 -0
  127. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/custom/test_transformer_runners.py +0 -0
  128. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/pii/__init__.py +0 -0
  129. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/pii/conftest.py +0 -0
  130. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/pii/sample_invoice.pdf +0 -0
  131. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/pii/test_pii_detector.py +0 -0
  132. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/pii/test_pii_detector_extended.py +0 -0
  133. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/secrets/__init__.py +0 -0
  134. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/secrets/test_secrets_detector.py +0 -0
  135. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/secrets/test_secrets_detector_extended.py +0 -0
  136. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/test_base_detector.py +0 -0
  137. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/test_custom_detector_examples_runtime.py +0 -0
  138. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/test_detector_catalog_commercial.py +0 -0
  139. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/test_detector_pipeline_types.py +0 -0
  140. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/test_detector_schema_examples.py +0 -0
  141. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/test_detector_types.py +0 -0
  142. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/test_phase2_detectors.py +0 -0
  143. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/test_registry.py +0 -0
  144. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/threat/__init__.py +0 -0
  145. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/threat/test_code_security_detector.py +0 -0
  146. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/detectors/threat/test_yara_detector.py +0 -0
  147. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/integration/test_wordpress_broken_links_detector.py +0 -0
  148. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/integration/test_wordpress_links_assets.py +0 -0
  149. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/pipeline/test_detector_pipeline.py +0 -0
  150. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/pipeline/test_worker_pool.py +0 -0
  151. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_azure_blob_storage_source.py +0 -0
  152. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_base_source_attachment.py +0 -0
  153. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_base_source_sampling.py +0 -0
  154. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_confluence_source.py +0 -0
  155. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_custom_extractor.py +0 -0
  156. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_databricks_source.py +0 -0
  157. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_google_cloud_storage_source.py +0 -0
  158. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_hashing.py +0 -0
  159. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_hive_source.py +0 -0
  160. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_jira_source.py +0 -0
  161. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_mongodb_source.py +0 -0
  162. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_mssql_source.py +0 -0
  163. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_mysql_source.py +0 -0
  164. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_neo4j_source.py +0 -0
  165. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_oracle_source.py +0 -0
  166. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_outputs.py +0 -0
  167. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_postgresql_source.py +0 -0
  168. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_powerbi_source.py +0 -0
  169. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_recipe_normalizer.py +0 -0
  170. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_s3_compatible_storage_source.py +0 -0
  171. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_sandbox_runner.py +0 -0
  172. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_servicedesk_source.py +0 -0
  173. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_slack_source.py +0 -0
  174. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_snowflake_source.py +0 -0
  175. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_source_dependency_groups.py +0 -0
  176. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_sqlite_source.py +0 -0
  177. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_tableau_source.py +0 -0
  178. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_tabular_utils.py +0 -0
  179. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/test_wordpress_source.py +0 -0
  180. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/utils/test_content_extraction.py +0 -0
  181. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/utils/test_embedded_images.py +0 -0
  182. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/utils/test_file_parser.py +0 -0
  183. {classifyre_cli-0.4.11 → classifyre_cli-0.4.12}/tests/utils/test_file_to_images.py +0 -0
@@ -1,3 +1,3 @@
1
1
  $ uv sync
2
- Resolved 265 packages in 157ms
2
+ Resolved 267 packages in 181ms
3
3
  Checked 50 packages in 1ms
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: classifyre-cli
3
- Version: 0.4.11
3
+ Version: 0.4.12
4
4
  Summary: Classifyre CLI — scan and classify unstructured data sources
5
5
  License: MIT
6
6
  Keywords: data,ingestion,metadata,pii,secrets,unstructured
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classifyre/cli",
3
- "version": "0.4.11",
3
+ "version": "0.4.12",
4
4
  "private": true,
5
5
  "scripts": {
6
6
  "build": "uv sync",
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "classifyre-cli"
3
- version = "0.4.11"
3
+ version = "0.4.12"
4
4
  description = "Classifyre CLI — scan and classify unstructured data sources"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -1078,9 +1078,10 @@ class DatabricksAuthMode(StrEnum):
1078
1078
 
1079
1079
  PAT_TOKEN = 'PAT_TOKEN'
1080
1080
  SERVICE_PRINCIPAL = 'SERVICE_PRINCIPAL'
1081
+ AZURE_SERVICE_PRINCIPAL = 'AZURE_SERVICE_PRINCIPAL'
1081
1082
 
1082
1083
 
1083
- class DatabricksRequiredPat(BaseModel):
1084
+ class PersonalAccessToken(BaseModel):
1084
1085
  model_config = ConfigDict(
1085
1086
  extra='forbid',
1086
1087
  )
@@ -1094,7 +1095,7 @@ class DatabricksRequiredPat(BaseModel):
1094
1095
  )
1095
1096
 
1096
1097
 
1097
- class DatabricksRequiredServicePrincipal(BaseModel):
1098
+ class ServicePrincipalOAuthM2M(BaseModel):
1098
1099
  model_config = ConfigDict(
1099
1100
  extra='forbid',
1100
1101
  )
@@ -1109,6 +1110,24 @@ class DatabricksRequiredServicePrincipal(BaseModel):
1109
1110
  client_id: str = Field(..., description='Databricks service principal client ID')
1110
1111
 
1111
1112
 
1113
+ class AzureServicePrincipal(BaseModel):
1114
+ model_config = ConfigDict(
1115
+ extra='forbid',
1116
+ )
1117
+ auth_mode: Literal['AZURE_SERVICE_PRINCIPAL']
1118
+ workspace_url: AnyUrl = Field(
1119
+ ...,
1120
+ description='Azure Databricks workspace URL (for example, https://adb-1234567890123456.7.azuredatabricks.net)',
1121
+ )
1122
+ warehouse_id: str = Field(
1123
+ ..., description='Databricks SQL warehouse ID used for sampling queries'
1124
+ )
1125
+ client_id: str = Field(
1126
+ ..., description='Azure AD application (client) ID for the service principal'
1127
+ )
1128
+ tenant_id: str = Field(..., description='Azure AD tenant ID')
1129
+
1130
+
1112
1131
  class DatabricksMaskedPat(BaseModel):
1113
1132
  model_config = ConfigDict(
1114
1133
  extra='forbid',
@@ -1125,6 +1144,15 @@ class DatabricksMaskedServicePrincipal(BaseModel):
1125
1144
  )
1126
1145
 
1127
1146
 
1147
+ class DatabricksMaskedAzureServicePrincipal(BaseModel):
1148
+ model_config = ConfigDict(
1149
+ extra='forbid',
1150
+ )
1151
+ client_secret: str = Field(
1152
+ ..., description='Azure AD client secret for the service principal'
1153
+ )
1154
+
1155
+
1128
1156
  class DatabricksOptionalConnection(BaseModel):
1129
1157
  """
1130
1158
  Databricks API and SQL statement execution tuning options.
@@ -2020,8 +2048,8 @@ class DatabricksInput(CoreInput):
2020
2048
  type: Literal['DATABRICKS'] = Field(
2021
2049
  'DATABRICKS', description='Type of the asset or source'
2022
2050
  )
2023
- required: DatabricksRequiredPat | DatabricksRequiredServicePrincipal = Field(
2024
- ..., title='DatabricksRequired'
2051
+ required: PersonalAccessToken | ServicePrincipalOAuthM2M | AzureServicePrincipal = (
2052
+ Field(..., title='DatabricksRequired')
2025
2053
  )
2026
2054
  masked: DatabricksMaskedPat | DatabricksMaskedServicePrincipal = Field(
2027
2055
  ..., title='DatabricksMasked'
@@ -13,16 +13,18 @@ from urllib.parse import urlparse
13
13
  import requests
14
14
 
15
15
  from ...models.generated_input import (
16
+ AzureServicePrincipal,
16
17
  DatabricksInput,
18
+ DatabricksMaskedAzureServicePrincipal,
17
19
  DatabricksMaskedPat,
18
20
  DatabricksMaskedServicePrincipal,
19
21
  DatabricksOptionalConnection,
20
22
  DatabricksOptionalExtraction,
21
23
  DatabricksOptionalScope,
22
- DatabricksRequiredPat,
23
- DatabricksRequiredServicePrincipal,
24
+ PersonalAccessToken,
24
25
  SamplingConfig,
25
26
  SamplingStrategy,
27
+ ServicePrincipalOAuthM2M,
26
28
  )
27
29
  from ...models.generated_single_asset_scan_results import (
28
30
  AssetType as OutputAssetType,
@@ -106,14 +108,20 @@ class DatabricksSource(BaseTabularSource):
106
108
  required = self.config.required
107
109
  masked = self.config.masked
108
110
 
109
- if isinstance(required, DatabricksRequiredPat):
111
+ if isinstance(required, PersonalAccessToken):
110
112
  if not isinstance(masked, DatabricksMaskedPat):
111
113
  raise ValueError("DATABRICKS PAT_TOKEN auth requires masked.token")
112
114
  return
113
- if isinstance(required, DatabricksRequiredServicePrincipal):
115
+ if isinstance(required, ServicePrincipalOAuthM2M):
114
116
  if not isinstance(masked, DatabricksMaskedServicePrincipal):
115
117
  raise ValueError("DATABRICKS SERVICE_PRINCIPAL auth requires masked.client_secret")
116
118
  return
119
+ if isinstance(required, AzureServicePrincipal):
120
+ if not isinstance(masked, DatabricksMaskedAzureServicePrincipal):
121
+ raise ValueError(
122
+ "DATABRICKS AZURE_SERVICE_PRINCIPAL auth requires masked.client_secret"
123
+ )
124
+ return
117
125
  raise ValueError("Unsupported DATABRICKS auth configuration")
118
126
 
119
127
  # ── Identity ─────────────────────────────────────────────────────────
@@ -163,7 +171,10 @@ class DatabricksSource(BaseTabularSource):
163
171
  return int(self._connection_options().statement_timeout_seconds or 60)
164
172
 
165
173
  def _is_pat_mode(self) -> bool:
166
- return isinstance(self.config.required, DatabricksRequiredPat)
174
+ return isinstance(self.config.required, PersonalAccessToken)
175
+
176
+ def _is_azure_sp_mode(self) -> bool:
177
+ return isinstance(self.config.required, AzureServicePrincipal)
167
178
 
168
179
  def _masked_pat_token(self) -> str:
169
180
  masked = self.config.masked
@@ -174,12 +185,23 @@ class DatabricksSource(BaseTabularSource):
174
185
  def _service_principal_credentials(self) -> tuple[str, str]:
175
186
  required = self.config.required
176
187
  masked = self.config.masked
177
- if not isinstance(required, DatabricksRequiredServicePrincipal):
188
+ if not isinstance(required, ServicePrincipalOAuthM2M):
178
189
  raise ValueError("SERVICE_PRINCIPAL auth mode is required")
179
190
  if not isinstance(masked, DatabricksMaskedServicePrincipal):
180
191
  raise ValueError("DATABRICKS SERVICE_PRINCIPAL auth requires masked.client_secret")
181
192
  return required.client_id, masked.client_secret
182
193
 
194
+ def _azure_sp_credentials(self) -> tuple[str, str, str]:
195
+ required = self.config.required
196
+ masked = self.config.masked
197
+ if not isinstance(required, AzureServicePrincipal):
198
+ raise ValueError("AZURE_SERVICE_PRINCIPAL auth mode is required")
199
+ if not isinstance(masked, DatabricksMaskedAzureServicePrincipal):
200
+ raise ValueError(
201
+ "DATABRICKS AZURE_SERVICE_PRINCIPAL auth requires masked.client_secret"
202
+ )
203
+ return required.tenant_id, required.client_id, masked.client_secret
204
+
183
205
  def _is_access_token_expired(self) -> bool:
184
206
  if self._access_token_expiry is None:
185
207
  return True
@@ -206,12 +228,38 @@ class DatabricksSource(BaseTabularSource):
206
228
  self._access_token_expiry = datetime.now(UTC) + timedelta(seconds=max(expires_in - 300, 0))
207
229
  return token.strip()
208
230
 
231
+ def _acquire_azure_token(self) -> str:
232
+ # Azure AD v1 token endpoint; resource ID is the fixed Databricks app in Azure
233
+ _databricks_azure_resource = "2ff814a6-3304-4ab8-85cb-cd0e6f879c1d"
234
+ tenant_id, client_id, client_secret = self._azure_sp_credentials()
235
+ response = self.session.post(
236
+ f"https://login.microsoftonline.com/{tenant_id}/oauth2/token",
237
+ data={
238
+ "grant_type": "client_credentials",
239
+ "client_id": client_id,
240
+ "client_secret": client_secret,
241
+ "resource": _databricks_azure_resource,
242
+ },
243
+ timeout=self._timeout_seconds(),
244
+ )
245
+ response.raise_for_status()
246
+ payload = response.json()
247
+ token = payload.get("access_token")
248
+ if not isinstance(token, str) or not token.strip():
249
+ raise ValueError("Azure AD token response did not include access_token")
250
+ expires_in = int(payload.get("expires_in", 3600))
251
+ self._access_token_expiry = datetime.now(UTC) + timedelta(seconds=max(expires_in - 300, 0))
252
+ return token.strip()
253
+
209
254
  def _access_token_value(self) -> str:
210
255
  if self._is_pat_mode():
211
256
  return self._masked_pat_token().strip()
212
257
  if self._access_token and not self._is_access_token_expired():
213
258
  return self._access_token
214
- self._access_token = self._acquire_service_principal_token()
259
+ if self._is_azure_sp_mode():
260
+ self._access_token = self._acquire_azure_token()
261
+ else:
262
+ self._access_token = self._acquire_service_principal_token()
215
263
  return self._access_token
216
264
 
217
265
  def _authorization_header(self) -> str:
@@ -860,7 +908,12 @@ class DatabricksSource(BaseTabularSource):
860
908
  with conn.cursor() as cursor:
861
909
  cursor.execute("SELECT 1")
862
910
  cursor.fetchone()
863
- auth_mode = "PAT_TOKEN" if self._is_pat_mode() else "SERVICE_PRINCIPAL"
911
+ if self._is_pat_mode():
912
+ auth_mode = "PAT_TOKEN"
913
+ elif self._is_azure_sp_mode():
914
+ auth_mode = "AZURE_SERVICE_PRINCIPAL"
915
+ else:
916
+ auth_mode = "SERVICE_PRINCIPAL"
864
917
  result["status"] = "SUCCESS"
865
918
  result["message"] = (
866
919
  "Successfully connected to Databricks Unity Catalog "